Decompiled source of SineusModdingApi v1.1.0

plugins/SineusModding.Api.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SineusArena;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Tables;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("SineusModding.Api")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e3a20ef5e1ad0ee6bacd755d20e53d57d7b892f2")]
[assembly: AssemblyProduct("SineusModding.Api")]
[assembly: AssemblyTitle("SineusModding.Api")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SineusModding.Api
{
	public readonly struct BountyKillInfo
	{
		public readonly Vector3 Position;

		public BountyKillInfo(Vector3 position)
		{
			//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;
		}
	}
	public static class BountyMobs
	{
		private static readonly HashSet<Unit> TrackedUnits = new HashSet<Unit>();

		private static bool _subscribed;

		private static readonly ManualLogSource Log = Logger.CreateLogSource("SineusModding.Api.BountyMobs");

		public static int TrackedAliveCount => TrackedUnits.Count;

		public static event Action<BountyKillInfo> BountyUnitKilled;

		public static void EnsureSubscribed()
		{
			if (!_subscribed)
			{
				PlayerSurvivalSpawner.OnSurvivalEnemySpawned = (Action<Unit>)Delegate.Combine(PlayerSurvivalSpawner.OnSurvivalEnemySpawned, new Action<Unit>(OnSurvivalUnitSpawned));
				Unit.unitDiedAllClients += OnUnitDied;
				_subscribed = true;
				Log.LogInfo((object)"Subscribed to PlayerSurvivalSpawner.OnSurvivalEnemySpawned and Unit.unitDiedAllClients.");
			}
		}

		private static void OnSurvivalUnitSpawned(Unit unit)
		{
			if (!((Object)(object)unit == (Object)null) && !unit.isBoss && IsEndlessNight())
			{
				TrackedUnits.Add(unit);
			}
		}

		private static bool IsEndlessNight()
		{
			try
			{
				return (Object)(object)DayNightController.I != (Object)null && DayNightController.I.IsEndlessNight;
			}
			catch
			{
				return false;
			}
		}

		private static void OnUnitDied(Unit unit)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			if (!((Object)(object)unit == (Object)null) && TrackedUnits.Remove(unit))
			{
				Vector3 position = (((Object)(object)((Component)unit).transform != (Object)null) ? ((Component)unit).transform.position : Vector3.zero);
				BountyMobs.BountyUnitKilled?.Invoke(new BountyKillInfo(position));
			}
		}
	}
	public static class BountyRewards
	{
		private static readonly ManualLogSource Log = Logger.CreateLogSource("SineusModding.Api.BountyRewards");

		private static bool _loggedClientSkip;

		public static void GrantCoins(PlayerTeam team, float amount)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (!(amount <= 0f))
			{
				PlayerCoinCounter val = SafeGet(() => PlayerCoinCounter.I);
				if ((Object)(object)val == (Object)null)
				{
					Log.LogWarning((object)"GrantCoins: PlayerCoinCounter.I is unavailable - no coins granted.");
				}
				else
				{
					val.AddCoins(team, amount);
				}
			}
		}

		public static void SpawnFreeChestAt(Vector3 position)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			GoldChestsManager val = SafeGet(() => GoldChestsManager.I);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"SpawnFreeChestAt: GoldChestsManager.I is unavailable - no chest spawned.");
				return;
			}
			if (!IsServer())
			{
				Log.LogInfo((object)"SpawnFreeChestAt: skipped, this client is not the host (chest is spawned by whichever machine is hosting).");
				return;
			}
			val.SpawnChestAt(position, (ChestType)1);
			Log.LogInfo((object)$"Spawned free chest at {position}.");
		}

		public static void SpawnRandomCustomDropAt(Vector3 position)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			CustomItemDropService val = SafeGet(() => CustomItemDropService.I);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)"SpawnRandomCustomDropAt: CustomItemDropService.I is unavailable - no item spawned.");
				return;
			}
			if (!IsServer())
			{
				Log.LogInfo((object)"SpawnRandomCustomDropAt: skipped, this client is not the host (items are spawned by whichever machine is hosting).");
				return;
			}
			GameObject val2 = PickWeightedDropPrefab(val.DropTable);
			if ((Object)(object)val2 == (Object)null)
			{
				Log.LogInfo((object)"SpawnRandomCustomDropAt: drop table is empty or every entry rolled a miss - nothing spawned this time.");
				return;
			}
			val.SpawnItem(position, val2);
			Log.LogInfo((object)$"Spawned custom drop '{((Object)val2).name}' at {position}.");
		}

		public static void SpawnBuildingUpgradeAt(Vector3 position)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!AnyBuildingUpgradeAvailable())
			{
				Log.LogInfo((object)"SpawnBuildingUpgradeAt: skipped, every player's buildings are already maxed with no open building spot left.");
			}
			else
			{
				SpawnFirstMatchingCustomDrop<CollectableItemBuilderUpgrade>(position, "building upgrade");
			}
		}

		public static bool AnyBuildingUpgradeAvailable()
		{
			//IL_0028: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Invalid comparison between Unknown and I4
			try
			{
				PlayerBaseManager i = PlayerBaseManager.I;
				if ((Object)(object)i == (Object)null)
				{
					return true;
				}
				foreach (PlayerTeam activePlayerTeam in GetActivePlayerTeams())
				{
					foreach (PlayerBuilding playerBuilding in i.GetPlayerBuildings(activePlayerTeam))
					{
						if ((Object)(object)playerBuilding != (Object)null && (Object)(object)playerBuilding.LevelModule != (Object)null && !playerBuilding.LevelModule.IsMaxLevel)
						{
							return true;
						}
					}
					foreach (BuildingSpot buildingSpot in i.GetBuildingSpots(activePlayerTeam))
					{
						if ((Object)(object)buildingSpot != (Object)null && (int)buildingSpot.BuildingSize == 300 && !buildingSpot.IsBuilt && (Object)(object)buildingSpot.Interactable != (Object)null && buildingSpot.Interactable.isEnabled)
						{
							return true;
						}
					}
				}
				return false;
			}
			catch
			{
				return true;
			}
		}

		public static void SpawnMagnetAt(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			SpawnFirstMatchingCustomDrop<CollectableItemMagnet>(position, "magnet");
		}

		private static void SpawnFirstMatchingCustomDrop<T>(Vector3 position, string logName) where T : Component
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			CustomItemDropService val = SafeGet(() => CustomItemDropService.I);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogWarning((object)("Spawn" + logName + ": CustomItemDropService.I is unavailable - nothing spawned."));
				return;
			}
			if (!IsServer())
			{
				Log.LogInfo((object)("Spawn" + logName + ": skipped, this client is not the host."));
				return;
			}
			GameObject val2 = null;
			foreach (CustomDropEntry item in val.DropTable)
			{
				if (item != null && (Object)(object)item.prefab != (Object)null && (Object)(object)item.prefab.GetComponent<T>() != (Object)null)
				{
					val2 = item.prefab;
					break;
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				Log.LogInfo((object)("SpawnFirstMatchingCustomDrop: no " + logName + " prefab found in the drop table - nothing spawned."));
				return;
			}
			val.SpawnItem(position, val2);
			Log.LogInfo((object)$"Spawned {logName} ('{((Object)val2).name}') at {position}.");
		}

		private static GameObject PickWeightedDropPrefab(List<CustomDropEntry> dropTable)
		{
			float num = 0f;
			foreach (CustomDropEntry item in dropTable)
			{
				if (item != null && (Object)(object)item.prefab != (Object)null && item.dropChancePercent > 0f)
				{
					num += item.dropChancePercent;
				}
			}
			if (num <= 0f)
			{
				return null;
			}
			float num2 = Random.Range(0f, num);
			float num3 = 0f;
			foreach (CustomDropEntry item2 in dropTable)
			{
				if (item2 != null && !((Object)(object)item2.prefab == (Object)null) && !(item2.dropChancePercent <= 0f))
				{
					num3 += item2.dropChancePercent;
					if (num2 <= num3)
					{
						return item2.prefab;
					}
				}
			}
			return null;
		}

		public static PlayerTeam GetLocalPlayerTeam()
		{
			//IL_001d: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerGameDataManager i = PlayerGameDataManager.I;
				return (PlayerTeam)((!((Object)(object)i == (Object)null)) ? ((int)i.localPlayerTeam) : 0);
			}
			catch
			{
				return (PlayerTeam)0;
			}
		}

		public static List<PlayerTeam> GetActivePlayerTeams()
		{
			//IL_003d: 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)
			List<PlayerTeam> list = new List<PlayerTeam>();
			try
			{
				PlayerGameDataManager i = PlayerGameDataManager.I;
				if ((Object)(object)i == (Object)null)
				{
					return list;
				}
				foreach (Unit allPlayerUnit in i.GetAllPlayerUnits())
				{
					if ((Object)(object)allPlayerUnit != (Object)null && !list.Contains(allPlayerUnit.Team))
					{
						list.Add(allPlayerUnit.Team);
					}
				}
			}
			catch
			{
			}
			return list;
		}

		public static void GrantCoinsToAllPlayers(float amount)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (amount <= 0f)
			{
				return;
			}
			if (!IsServer())
			{
				if (!_loggedClientSkip)
				{
					_loggedClientSkip = true;
					Log.LogInfo((object)"GrantCoinsToAllPlayers: skipped, this client is not the host (rewards are granted by whichever machine is hosting). This will not be logged again this session.");
				}
				return;
			}
			foreach (PlayerTeam activePlayerTeam in GetActivePlayerTeams())
			{
				GrantCoins(activePlayerTeam, amount);
			}
		}

		private static bool IsServer()
		{
			try
			{
				return (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer;
			}
			catch
			{
				return false;
			}
		}

		private static T SafeGet<T>(Func<T> getter) where T : class
		{
			try
			{
				return getter();
			}
			catch
			{
				return null;
			}
		}
	}
	public static class ChoicePanel
	{
		private static UIRandBuffSelectionPanel _cachedPanel;

		private static FieldInfo _fRerolls;

		private static FieldInfo _fSkips;

		private static FieldInfo _fBans;

		private static FieldInfo _fActiveRequest;

		private static FieldInfo _fButtonsLayout;

		private static FieldInfo _fRerollButton;

		private static FieldInfo _fSkipButton;

		private static FieldInfo _fBanButton;

		private static bool _reflectionInitialized;

		public static bool TryGetCounts(out int rerolls, out int skips, out int bans)
		{
			rerolls = 0;
			skips = 0;
			bans = 0;
			try
			{
				EnsureReflection();
				if (_fActiveRequest == null || _fButtonsLayout == null)
				{
					return false;
				}
				if ((Object)(object)_cachedPanel == (Object)null)
				{
					_cachedPanel = Object.FindAnyObjectByType<UIRandBuffSelectionPanel>((FindObjectsInactive)1);
					if ((Object)(object)_cachedPanel == (Object)null)
					{
						return false;
					}
				}
				object? value = _fActiveRequest.GetValue(_cachedPanel);
				object? value2 = _fButtonsLayout.GetValue(_cachedPanel);
				GameObject val = (GameObject)((value2 is GameObject) ? value2 : null);
				if (value == null || (Object)(object)val == (Object)null || !val.activeInHierarchy)
				{
					return false;
				}
				rerolls = ResolveCount(_fRerolls, "Bonus_Reroll");
				skips = ResolveCount(_fSkips, "Bonus_Skip");
				bans = ResolveCount(_fBans, "Bonus_Ban");
				return true;
			}
			catch
			{
				_cachedPanel = null;
				return false;
			}
		}

		private static int ResolveCount(FieldInfo field, string bonusId)
		{
			int num = ((field == null) ? (-1) : ((int)field.GetValue(_cachedPanel)));
			if (num >= 0)
			{
				return num;
			}
			try
			{
				if ((Object)(object)ConfigManager.I != (Object)null && ConfigManager.I.IsInDemoMode)
				{
					return 3;
				}
			}
			catch
			{
			}
			try
			{
				LocalBonusRepository i = LocalBonusRepository.I;
				return (!((Object)(object)i == (Object)null)) ? i.GetLevel(bonusId) : 0;
			}
			catch
			{
				return 0;
			}
		}

		private static void EnsureReflection()
		{
			if (!_reflectionInitialized)
			{
				_reflectionInitialized = true;
				Type? typeFromHandle = typeof(UIRandBuffSelectionPanel);
				_fRerolls = typeFromHandle.GetField("_rerollsRemaining", BindingFlags.Instance | BindingFlags.NonPublic);
				_fSkips = typeFromHandle.GetField("_skipsRemaining", BindingFlags.Instance | BindingFlags.NonPublic);
				_fBans = typeFromHandle.GetField("_bansRemaining", BindingFlags.Instance | BindingFlags.NonPublic);
				_fActiveRequest = typeFromHandle.GetField("activeRequest", BindingFlags.Instance | BindingFlags.NonPublic);
				_fButtonsLayout = typeFromHandle.GetField("buttonsLayout", BindingFlags.Instance | BindingFlags.NonPublic);
				_fRerollButton = typeFromHandle.GetField("rerollButton", BindingFlags.Instance | BindingFlags.NonPublic);
				_fSkipButton = typeFromHandle.GetField("skipButton", BindingFlags.Instance | BindingFlags.NonPublic);
				_fBanButton = typeFromHandle.GetField("banPerSessionButton", BindingFlags.Instance | BindingFlags.NonPublic);
			}
		}

		public static bool TryGetActionStackScreenRect(out Rect screenRect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_0095: 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)
			screenRect = default(Rect);
			try
			{
				EnsureReflection();
				if ((Object)(object)_cachedPanel == (Object)null)
				{
					return false;
				}
				bool any = false;
				Rect union = default(Rect);
				AccumulateButtonRect(_fRerollButton, ref union, ref any);
				AccumulateButtonRect(_fSkipButton, ref union, ref any);
				AccumulateButtonRect(_fBanButton, ref union, ref any);
				if (!any && _fButtonsLayout != null)
				{
					object? value = _fButtonsLayout.GetValue(_cachedPanel);
					GameObject val = (GameObject)((value is GameObject) ? value : null);
					if (val != null && val.activeInHierarchy)
					{
						Transform transform = val.transform;
						RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
						if (val2 != null)
						{
							union = GuiRectOf(val2);
							any = true;
						}
					}
				}
				screenRect = union;
				return any;
			}
			catch
			{
				return false;
			}
		}

		private static void AccumulateButtonRect(FieldInfo buttonField, ref Rect union, ref bool any)
		{
			//IL_005b: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			if (TryGetButtonRect(buttonField, out var screenRect))
			{
				union = (any ? Rect.MinMaxRect(Mathf.Min(((Rect)(ref union)).xMin, ((Rect)(ref screenRect)).xMin), Mathf.Min(((Rect)(ref union)).yMin, ((Rect)(ref screenRect)).yMin), Mathf.Max(((Rect)(ref union)).xMax, ((Rect)(ref screenRect)).xMax), Mathf.Max(((Rect)(ref union)).yMax, ((Rect)(ref screenRect)).yMax)) : screenRect);
				any = true;
			}
		}

		private static bool TryGetButtonRect(FieldInfo buttonField, out Rect screenRect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			screenRect = default(Rect);
			if (!(buttonField == null))
			{
				object? value = buttonField.GetValue(_cachedPanel);
				Component val = (Component)((value is Component) ? value : null);
				if (val != null && !((Object)(object)val == (Object)null) && val.gameObject.activeInHierarchy)
				{
					Transform transform = val.transform;
					RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					if (val2 != null)
					{
						screenRect = GuiRectOf(val2);
						return true;
					}
				}
			}
			return false;
		}

		public static bool TryGetRerollButtonScreenRect(out Rect screenRect)
		{
			EnsureReflectionSafe();
			return TryGetButtonRect(_fRerollButton, out screenRect);
		}

		public static bool TryGetSkipButtonScreenRect(out Rect screenRect)
		{
			EnsureReflectionSafe();
			return TryGetButtonRect(_fSkipButton, out screenRect);
		}

		public static bool TryGetBanButtonScreenRect(out Rect screenRect)
		{
			EnsureReflectionSafe();
			return TryGetButtonRect(_fBanButton, out screenRect);
		}

		private static void EnsureReflectionSafe()
		{
			try
			{
				EnsureReflection();
				if ((Object)(object)_cachedPanel == (Object)null)
				{
					_cachedPanel = Object.FindAnyObjectByType<UIRandBuffSelectionPanel>((FindObjectsInactive)1);
				}
			}
			catch
			{
			}
		}

		private static Rect GuiRectOf(RectTransform rectTransform)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			rectTransform.GetWorldCorners(array);
			Canvas componentInParent = ((Component)rectTransform).GetComponentInParent<Canvas>();
			Camera cam = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
			Vector2 val = WorldToGuiPoint(array[0], cam);
			Vector2 val2 = WorldToGuiPoint(array[2], cam);
			return Rect.MinMaxRect(Mathf.Min(val.x, val2.x), Mathf.Min(val.y, val2.y), Mathf.Max(val.x, val2.x), Mathf.Max(val.y, val2.y));
		}

		private static Vector2 WorldToGuiPoint(Vector3 worldPoint, Camera cam)
		{
			//IL_0012: 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)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)cam == (Object)null) ? worldPoint : cam.WorldToScreenPoint(worldPoint));
			return new Vector2(val.x, (float)Screen.height - val.y);
		}
	}
	public static class CombatMeter
	{
		private readonly struct Sample
		{
			public readonly float Time;

			public readonly float CumulativeDamage;

			public readonly int CumulativeKills;

			public Sample(float time, float cumulativeDamage, int cumulativeKills)
			{
				Time = time;
				CumulativeDamage = cumulativeDamage;
				CumulativeKills = cumulativeKills;
			}
		}

		private const float DpsWindowSeconds = 10f;

		private const float CombatBurstIdleSeconds = 3f;

		private static readonly List<Sample> Samples = new List<Sample>();

		private static float lastCumulativeDamage;

		private static float lastDamageTime = -999f;

		private static float burstStartDamage;

		private static float burstStartTime = -999f;

		private static float lastSampleTime = -999f;

		public static void Tick()
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - lastSampleTime < 0.1f)
			{
				return;
			}
			lastSampleTime = unscaledTime;
			float totalDamage = LocalPlayerProgress.GetTotalDamage();
			int kills = LocalPlayerProgress.GetKills();
			if (totalDamage > lastCumulativeDamage)
			{
				if (unscaledTime - lastDamageTime > 3f)
				{
					burstStartDamage = lastCumulativeDamage;
					burstStartTime = unscaledTime;
				}
				lastDamageTime = unscaledTime;
			}
			lastCumulativeDamage = totalDamage;
			Samples.Add(new Sample(unscaledTime, totalDamage, kills));
			float num = unscaledTime - 10f;
			int i;
			for (i = 0; i < Samples.Count && Samples[i].Time < num; i++)
			{
			}
			if (i > 0)
			{
				Samples.RemoveRange(0, i);
			}
		}

		public static float GetDps()
		{
			if (Samples.Count < 2)
			{
				return 0f;
			}
			Sample sample = Samples[0];
			Sample sample2 = Samples[Samples.Count - 1];
			float num = sample2.Time - sample.Time;
			if (num <= 0.01f)
			{
				return 0f;
			}
			return (sample2.CumulativeDamage - sample.CumulativeDamage) / num;
		}

		public static float GetKillsPerMinute()
		{
			if (Samples.Count < 2)
			{
				return 0f;
			}
			Sample sample = Samples[0];
			Sample sample2 = Samples[Samples.Count - 1];
			float num = sample2.Time - sample.Time;
			if (num <= 0.01f)
			{
				return 0f;
			}
			return (float)(sample2.CumulativeKills - sample.CumulativeKills) / num * 60f;
		}

		public static float GetCurrentComboDamage()
		{
			if (!(Time.unscaledTime - lastDamageTime <= 3f))
			{
				return 0f;
			}
			return Mathf.Max(0f, lastCumulativeDamage - burstStartDamage);
		}

		public static float GetTimeSinceLastHit()
		{
			if (lastDamageTime < 0f)
			{
				return -1f;
			}
			return Mathf.Max(0f, Time.unscaledTime - lastDamageTime);
		}
	}
	public static class DamageSourceCapture
	{
		private static readonly Dictionary<string, float> LocalDamageBySource = new Dictionary<string, float>(StringComparer.Ordinal);

		private static Harmony _harmony;

		private static PlayerStatisticsManager _lastManager;

		public static void EnsureInstalled()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			if (_harmony == null)
			{
				_harmony = new Harmony("com.community.sineusmodding.api.damagesourcecapture");
				_harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerStatisticsManager), "AddDamage", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DamageSourceCapture), "OnAddDamage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void OnAddDamage(PlayerStatisticsManager __instance, PlayerTeam team, string sourceName, float amount)
		{
			//IL_003e: 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)
			if (__instance != _lastManager)
			{
				_lastManager = __instance;
				LocalDamageBySource.Clear();
			}
			if (!(amount <= 0f) && !string.IsNullOrEmpty(sourceName))
			{
				PlayerGameDataManager i;
				try
				{
					i = PlayerGameDataManager.I;
				}
				catch
				{
					return;
				}
				if (!((Object)(object)i == (Object)null) && team == i.localPlayerTeam)
				{
					LocalDamageBySource.TryGetValue(sourceName, out var value);
					LocalDamageBySource[sourceName] = value + amount;
				}
			}
		}

		public static IReadOnlyDictionary<string, float> GetLocalDamageBySource()
		{
			return LocalDamageBySource;
		}
	}
	public static class DpsMeterHook
	{
		private const string ControllerTypeName = "DpsMeter.DpsMeterController";

		private const float SearchRetryInterval = 2f;

		private static Component _controller;

		private static FieldInfo _fWindowRect;

		private static FieldInfo _fVisible;

		private static float _nextSearchTime;

		public static bool IsPresent
		{
			get
			{
				EnsureController();
				return (Object)(object)_controller != (Object)null;
			}
		}

		public static bool IsVisible
		{
			get
			{
				EnsureController();
				if ((Object)(object)_controller == (Object)null)
				{
					return false;
				}
				try
				{
					return _fVisible == null || (bool)_fVisible.GetValue(_controller);
				}
				catch
				{
					return false;
				}
			}
		}

		public static bool TryGetWindowScreenRect(out Rect screenRect)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			screenRect = default(Rect);
			EnsureController();
			if ((Object)(object)_controller == (Object)null || !IsVisible)
			{
				return false;
			}
			try
			{
				if (_fWindowRect != null)
				{
					object? value = _fWindowRect.GetValue(_controller);
					RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
					if (val != null)
					{
						screenRect = GuiRectOf(val);
						return true;
					}
				}
				return false;
			}
			catch
			{
				_controller = null;
				return false;
			}
		}

		private static void EnsureController()
		{
			if ((Object)(object)_controller != (Object)null || Time.unscaledTime < _nextSearchTime)
			{
				return;
			}
			_nextSearchTime = Time.unscaledTime + 2f;
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				for (int i = 0; i < assemblies.Length; i++)
				{
					Type type = assemblies[i].GetType("DpsMeter.DpsMeterController", throwOnError: false);
					if (!(type == null))
					{
						Object obj = Object.FindAnyObjectByType(type, (FindObjectsInactive)1);
						Component val = (Component)(object)((obj is Component) ? obj : null);
						if (val != null)
						{
							_fWindowRect = type.GetField("_windowRect", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
							_fVisible = type.GetField("_visible", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
							_controller = val;
							break;
						}
					}
				}
			}
			catch
			{
				_controller = null;
			}
		}

		private static Rect GuiRectOf(RectTransform rectTransform)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			rectTransform.GetWorldCorners(array);
			Canvas componentInParent = ((Component)rectTransform).GetComponentInParent<Canvas>();
			Camera cam = (((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0) ? componentInParent.worldCamera : null);
			Vector2 val = WorldToGuiPoint(array[0], cam);
			Vector2 val2 = WorldToGuiPoint(array[2], cam);
			return Rect.MinMaxRect(Mathf.Min(val.x, val2.x), Mathf.Min(val.y, val2.y), Mathf.Max(val.x, val2.x), Mathf.Max(val.y, val2.y));
		}

		private static Vector2 WorldToGuiPoint(Vector3 worldPoint, Camera cam)
		{
			//IL_0012: 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)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)cam == (Object)null) ? worldPoint : cam.WorldToScreenPoint(worldPoint));
			return new Vector2(val.x, (float)Screen.height - val.y);
		}
	}
	public readonly struct DamageSourceEntry
	{
		public readonly string SourceName;

		public readonly float Damage;

		public DamageSourceEntry(string sourceName, float damage)
		{
			SourceName = sourceName;
			Damage = damage;
		}
	}
	public readonly struct PresetLevelEntry
	{
		public readonly PresetInfo Preset;

		public readonly int Level;

		public PresetLevelEntry(PresetInfo preset, int level)
		{
			Preset = preset;
			Level = level;
		}
	}
	public static class LocalPlayerProgress
	{
		private static bool _subscribed;

		public static event Action Changed;

		public static void EnsureSubscribed()
		{
			if (!_subscribed && !((Object)(object)SafeGetManager() == (Object)null))
			{
				DamageSourceCapture.EnsureInstalled();
				PlayerStatisticsManager.KillsChanged += delegate
				{
					LocalPlayerProgress.Changed?.Invoke();
				};
				PlayerStatisticsManager.DamageBySourceChanged += delegate
				{
					LocalPlayerProgress.Changed?.Invoke();
				};
				PlayerStatisticsManager.WeaponLevelChanged += delegate
				{
					LocalPlayerProgress.Changed?.Invoke();
				};
				PlayerStatisticsManager.PassiveLevelChanged += delegate
				{
					LocalPlayerProgress.Changed?.Invoke();
				};
				PlayerStatisticsManager.ItemLevelChanged += delegate
				{
					LocalPlayerProgress.Changed?.Invoke();
				};
				_subscribed = true;
			}
		}

		public static int GetKills()
		{
			PlayerStatisticsManager val = SafeGetManager();
			if (!((Object)(object)val == (Object)null))
			{
				return val.GetLocalPlayerKills();
			}
			return 0;
		}

		public static float GetTotalDamage()
		{
			float num = 0f;
			foreach (DamageSourceEntry item in GetDamageBySource())
			{
				num += item.Damage;
			}
			return num;
		}

		public unsafe static List<DamageSourceEntry> GetDamageBySource()
		{
			//IL_003a: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			List<DamageSourceEntry> list = new List<DamageSourceEntry>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			IReadOnlyDictionary<string, float> localDamageBySource = DamageSourceCapture.GetLocalDamageBySource();
			PlayerStatisticsManager val = SafeGetManager();
			if ((Object)(object)val != (Object)null)
			{
				foreach (DamageSourceStatEntry localPlayerDamageBySourceStat in val.GetLocalPlayerDamageBySourceStats())
				{
					FixedString128Bytes sourceName = localPlayerDamageBySourceStat.SourceName;
					string text = ((object)(*(FixedString128Bytes*)(&sourceName))/*cast due to .constrained prefix*/).ToString();
					float value;
					float val2 = (localDamageBySource.TryGetValue(text, out value) ? value : 0f);
					list.Add(new DamageSourceEntry(text, Math.Max(localPlayerDamageBySourceStat.Damage, val2)));
					hashSet.Add(text);
				}
			}
			foreach (KeyValuePair<string, float> item in localDamageBySource)
			{
				if (!hashSet.Contains(item.Key))
				{
					list.Add(new DamageSourceEntry(item.Key, item.Value));
				}
			}
			return list;
		}

		public static List<PresetLevelEntry> GetWeaponLevels()
		{
			return ResolveLevels((PlayerStatisticsManager m) => m.GetLocalPlayerWeaponLevelStats());
		}

		public static List<PresetLevelEntry> GetPassiveLevels()
		{
			return ResolveLevels((PlayerStatisticsManager m) => m.GetLocalPlayerPassiveLevelStats());
		}

		public static List<PresetLevelEntry> GetItemLevels()
		{
			return ResolveLevels((PlayerStatisticsManager m) => m.GetLocalPlayerItemLevelStats());
		}

		private unsafe static List<PresetLevelEntry> ResolveLevels(Func<PlayerStatisticsManager, List<PresetLevelStatEntry>> getter)
		{
			//IL_0028: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			List<PresetLevelEntry> list = new List<PresetLevelEntry>();
			PlayerStatisticsManager val = SafeGetManager();
			if ((Object)(object)val == (Object)null)
			{
				return list;
			}
			foreach (PresetLevelStatEntry item in getter(val))
			{
				FixedString128Bytes key = item.Key;
				string systemId = ((object)(*(FixedString128Bytes*)(&key))/*cast due to .constrained prefix*/).ToString();
				list.Add(new PresetLevelEntry(PresetCatalog.Resolve(systemId), item.Level));
			}
			return list;
		}

		private static PlayerStatisticsManager SafeGetManager()
		{
			try
			{
				return PlayerStatisticsManager.I;
			}
			catch
			{
				return null;
			}
		}
	}
	public static class LocalPlayerStats
	{
		private static IStatsModule _cachedStats;

		private static Unit _cachedUnit;

		private static bool _subscribed;

		public static event Action Changed;

		public static bool TryGetValue(StatType statType, out float value)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			IStatsModule statsModule = GetStatsModule();
			if (statsModule == null)
			{
				value = 0f;
				return false;
			}
			value = ReadStat(statsModule, statType);
			return true;
		}

		public static IStatsModule GetStatsModule()
		{
			Unit val = SafeGetLocalUnit();
			if ((Object)(object)val == (Object)null)
			{
				Detach();
				return null;
			}
			if (val != _cachedUnit)
			{
				Detach();
				_cachedUnit = val;
				_cachedStats = val.Stats;
				Attach();
			}
			return _cachedStats;
		}

		public static bool TryGetCurrentHealth(out float current, out float max)
		{
			GetStatsModule();
			IDamageable val = (((Object)(object)_cachedUnit == (Object)null) ? null : _cachedUnit.Damageable);
			if (val == null)
			{
				current = 0f;
				max = 0f;
				return false;
			}
			current = val.CurrentHealth;
			max = val.MaxHealth;
			return true;
		}

		public static float GetHealthFraction()
		{
			if (!TryGetCurrentHealth(out var current, out var max) || !(max > 0f))
			{
				return 0f;
			}
			return Mathf.Clamp01(current / max);
		}

		private static void Attach()
		{
			if (_cachedStats != null && !_subscribed)
			{
				_cachedStats.StatsChanged += OnStatsChanged;
				_subscribed = true;
			}
		}

		private static void Detach()
		{
			if (_cachedStats != null && _subscribed)
			{
				_cachedStats.StatsChanged -= OnStatsChanged;
			}
			_subscribed = false;
			_cachedStats = null;
			_cachedUnit = null;
		}

		private static void OnStatsChanged()
		{
			LocalPlayerStats.Changed?.Invoke();
		}

		public static bool TryGetLocalUnitName(out string name)
		{
			Unit val = SafeGetLocalUnit();
			name = (((Object)(object)val == (Object)null) ? null : val.UnitName);
			return (Object)(object)val != (Object)null;
		}

		private static Unit SafeGetLocalUnit()
		{
			try
			{
				PlayerGameDataManager i = PlayerGameDataManager.I;
				return ((Object)(object)i == (Object)null) ? null : i.GetLocalPlayerUnit();
			}
			catch
			{
				return null;
			}
		}

		private static float ReadStat(IStatsModule stats, StatType statType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected I4, but got Unknown
			return (int)statType switch
			{
				0 => stats.MaxHealth, 
				1 => stats.DamageModifier, 
				2 => stats.Damage, 
				3 => stats.MovementSpeed, 
				4 => stats.AttackRange, 
				5 => stats.DamageReduction, 
				6 => stats.MaxStamina, 
				7 => stats.AttackSpeed, 
				8 => stats.HealthRegeneration, 
				9 => stats.RicochetCount, 
				10 => stats.Barrier, 
				11 => stats.Lifesteal, 
				12 => stats.Evasion, 
				14 => stats.CritChance, 
				15 => stats.CritDamage, 
				16 => stats.Size, 
				17 => stats.Cooldown, 
				18 => stats.ProjectileSpeed, 
				19 => stats.ElitesDamage, 
				20 => stats.Duration, 
				21 => stats.Knockback, 
				22 => stats.Mastery, 
				23 => stats.Magnet, 
				24 => stats.Luck, 
				25 => stats.ExperienceBonus, 
				26 => stats.Armor, 
				27 => stats.LifestealChance, 
				28 => stats.JumpsCount, 
				29 => stats.RepairSpeed, 
				30 => stats.ExpIncome, 
				31 => stats.GoldIncome, 
				32 => stats.BuildCostDiscount, 
				33 => stats.ProjectileCount, 
				34 => stats.Weight, 
				35 => stats.MaxTowerReserve, 
				36 => stats.TowerCooldown, 
				37 => stats.MaxLevel, 
				38 => stats.JumpHeight, 
				39 => stats.GoldByKill, 
				40 => stats.AltarChargeSpeed, 
				41 => stats.MegaCrit, 
				42 => stats.MetaCurrency, 
				43 => stats.ChestChance, 
				44 => stats.WeaponMaxLevel, 
				45 => stats.WeaponUpgradeChance, 
				_ => 0f, 
			};
		}
	}
	public static class MatchObjective
	{
		private static bool _subscribed;

		private static readonly FieldInfo _fFinalBossSiegeEndTime = typeof(DayNightController).GetField("_finalBossSiegeEndTimeNet", BindingFlags.Instance | BindingFlags.NonPublic);

		private static UILevelQuestPanel _cachedBannerPanel;

		private static RectTransform _cachedBannerRect;

		public static bool IsMatchActive
		{
			get
			{
				QuestStep step;
				return TryGetCurrentStep(out step);
			}
		}

		public static bool IsInMatch
		{
			get
			{
				try
				{
					return (Object)(object)GameStageManager.I != (Object)null;
				}
				catch
				{
					return false;
				}
			}
		}

		public static bool IsFinalBossSiege
		{
			get
			{
				try
				{
					return (Object)(object)DayNightController.I != (Object)null && DayNightController.I.IsFinalBossSiege;
				}
				catch
				{
					return false;
				}
			}
		}

		public static bool IsPostBossPhase
		{
			get
			{
				if (!IsFinalBossSiege)
				{
					return IsEndlessNight;
				}
				return true;
			}
		}

		public static float FinalBossSiegeSecondsRemaining
		{
			get
			{
				try
				{
					DayNightController i = DayNightController.I;
					if ((Object)(object)i == (Object)null || !i.IsFinalBossSiege)
					{
						return 0f;
					}
					NetworkVariable<float> val = (NetworkVariable<float>)_fFinalBossSiegeEndTime.GetValue(i);
					float elapsedTime = SessionTimerService.I.ElapsedTime;
					return Mathf.Max(0f, val.Value - elapsedTime);
				}
				catch
				{
					return 0f;
				}
			}
		}

		public static bool IsEndlessNight
		{
			get
			{
				try
				{
					return (Object)(object)DayNightController.I != (Object)null && DayNightController.I.IsEndlessNight;
				}
				catch
				{
					return false;
				}
			}
		}

		public static int CurrentStage
		{
			get
			{
				try
				{
					return ((Object)(object)GameStageManager.I != (Object)null) ? GameStageManager.I.CurrentStage : (-1);
				}
				catch
				{
					return -1;
				}
			}
		}

		public static event Action<QuestStep, QuestStep> StepChanged;

		public static event Action BossLairFound;

		public static void EnsureSubscribed()
		{
			if (!_subscribed)
			{
				LevelQuestManager.OnQuestStepChanged += OnStepChanged;
				BossLairFounder.OnBossLairFound += OnBossLairFound;
				_subscribed = true;
			}
		}

		public static bool TryGetCurrentStep(out QuestStep step)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected I4, but got Unknown
			try
			{
				LevelQuestManager i = LevelQuestManager.I;
				if ((Object)(object)i == (Object)null)
				{
					step = QuestStep.FindBossLair;
					return false;
				}
				step = (QuestStep)(int)i.CurrentStep;
				return true;
			}
			catch
			{
				step = QuestStep.FindBossLair;
				return false;
			}
		}

		public static bool TryGetObjectiveBannerScreenRect(out Rect screenRect)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0045: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)_cachedBannerRect == (Object)null)
				{
					_cachedBannerPanel = Object.FindAnyObjectByType<UILevelQuestPanel>((FindObjectsInactive)1);
					_cachedBannerRect = (((Object)(object)_cachedBannerPanel == (Object)null) ? null : ((Component)_cachedBannerPanel).GetComponent<RectTransform>());
				}
				if ((Object)(object)_cachedBannerRect == (Object)null)
				{
					screenRect = default(Rect);
					return false;
				}
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				_cachedBannerRect.GetWorldCorners(array);
				Camera cam = ResolveCanvasCamera(_cachedBannerRect);
				Vector2 val = WorldToGuiPoint(array[0], cam);
				Vector2 val2 = WorldToGuiPoint(array[2], cam);
				float num = Mathf.Min(val.x, val2.x);
				float num2 = Mathf.Min(val.y, val2.y);
				float num3 = Mathf.Abs(val2.x - val.x);
				float num4 = Mathf.Abs(val2.y - val.y);
				screenRect = new Rect(num, num2, num3, num4);
				return true;
			}
			catch
			{
				_cachedBannerPanel = null;
				_cachedBannerRect = null;
				screenRect = default(Rect);
				return false;
			}
		}

		private static Camera ResolveCanvasCamera(RectTransform rect)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			Canvas componentInParent = ((Component)rect).GetComponentInParent<Canvas>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return null;
			}
			if ((int)componentInParent.renderMode != 0)
			{
				return componentInParent.worldCamera;
			}
			return null;
		}

		private static Vector2 WorldToGuiPoint(Vector3 worldPoint, Camera cam)
		{
			//IL_0012: 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)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)cam == (Object)null) ? worldPoint : cam.WorldToScreenPoint(worldPoint));
			return new Vector2(val.x, (float)Screen.height - val.y);
		}

		private static void OnStepChanged(QuestStep oldStep, QuestStep newStep)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected I4, but got Unknown
			//IL_0011: Expected I4, but got Unknown
			MatchObjective.StepChanged?.Invoke((QuestStep)(int)oldStep, (QuestStep)(int)newStep);
		}

		private static void OnBossLairFound()
		{
			MatchObjective.BossLairFound?.Invoke();
		}
	}
	public enum QuestStep : byte
	{
		FindBossLair,
		SummonBoss,
		DefeatBoss,
		ActivateSvetoch,
		Completed
	}
	public static class MatchTimer
	{
		public static bool TryGetElapsedSeconds(out float seconds)
		{
			try
			{
				SessionTimerService i = SessionTimerService.I;
				if ((Object)(object)i == (Object)null)
				{
					seconds = 0f;
					return false;
				}
				seconds = i.ElapsedTime;
				return true;
			}
			catch
			{
				seconds = 0f;
				return false;
			}
		}

		public static string GetFormattedTime()
		{
			try
			{
				SessionTimerService i = SessionTimerService.I;
				return ((Object)(object)i == (Object)null) ? "00:00" : i.FormattedTime;
			}
			catch
			{
				return "00:00";
			}
		}
	}
	public static class NumberFormat
	{
		public static string Abbreviate(float value)
		{
			float num = ((value < 0f) ? (0f - value) : value);
			if (num >= 1000000f)
			{
				return $"{value / 1000000f:0.#}M";
			}
			if (num >= 1000f)
			{
				return $"{value / 1000f:0.#}k";
			}
			return $"{value:0.#}";
		}
	}
	public readonly struct PresetInfo
	{
		public readonly string SystemId;

		public readonly string DisplayName;

		public readonly Sprite Icon;

		public PresetInfo(string systemId, string displayName, Sprite icon)
		{
			SystemId = systemId;
			DisplayName = displayName;
			Icon = icon;
		}

		public static PresetInfo Unknown(string systemId)
		{
			return new PresetInfo(systemId, systemId, null);
		}
	}
	public static class PresetCatalog
	{
		private const string LocalizationTable = "Sineus_lore";

		private static Dictionary<string, PresetInfo> _cache;

		public static PresetInfo Resolve(string systemId)
		{
			if (string.IsNullOrEmpty(systemId))
			{
				return PresetInfo.Unknown(systemId);
			}
			EnsureBuilt();
			if (_cache.TryGetValue(systemId, out var value))
			{
				return value;
			}
			string text = TryLocalize(systemId);
			if (text == null)
			{
				return PresetInfo.Unknown(systemId);
			}
			return new PresetInfo(systemId, text, null);
		}

		private static string TryLocalize(string systemId)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string localizedString = new LocalizedString(TableReference.op_Implicit("Sineus_lore"), TableEntryReference.op_Implicit(systemId)).GetLocalizedString();
				return (string.IsNullOrEmpty(localizedString) || localizedString == systemId) ? null : localizedString;
			}
			catch
			{
				return null;
			}
		}

		public static void Invalidate()
		{
			_cache = null;
		}

		public static void Refresh()
		{
			_cache = BuildCache();
		}

		private static void EnsureBuilt()
		{
			if (_cache == null || _cache.Count == 0)
			{
				_cache = BuildCache() ?? new Dictionary<string, PresetInfo>();
			}
		}

		private static Dictionary<string, PresetInfo> BuildCache()
		{
			TeamUnitBuffPresetService i;
			try
			{
				i = TeamUnitBuffPresetService.I;
			}
			catch
			{
				return null;
			}
			if ((Object)(object)i == (Object)null)
			{
				return null;
			}
			Dictionary<string, PresetInfo> dictionary = new Dictionary<string, PresetInfo>(StringComparer.Ordinal);
			foreach (TeamUnitBuffPreset allPreset in i.GetAllPresets())
			{
				if (!((Object)(object)allPreset == (Object)null))
				{
					string systemId = allPreset.SystemId;
					if (!string.IsNullOrEmpty(systemId))
					{
						string displayName = SafeLocalizedName(allPreset);
						dictionary[systemId] = new PresetInfo(systemId, displayName, allPreset.icon);
					}
				}
			}
			return dictionary;
		}

		private static string SafeLocalizedName(TeamUnitBuffPreset preset)
		{
			try
			{
				string localizedName = preset.GetLocalizedName();
				return string.IsNullOrEmpty(localizedName) ? preset.displayName : localizedName;
			}
			catch
			{
				return preset.displayName;
			}
		}
	}
	public enum StatFormat
	{
		Integer,
		Decimal,
		Percent
	}
	public readonly struct StatDisplayInfo
	{
		public readonly StatType StatType;

		public readonly string Label;

		public readonly StatFormat Format;

		public StatDisplayInfo(StatType statType, string label, StatFormat format)
		{
			//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)
			StatType = statType;
			Label = label;
			Format = format;
		}

		public string FormatValue(float value)
		{
			switch (Format)
			{
			case StatFormat.Percent:
				return $"{value * 100f:0}%";
			case StatFormat.Decimal:
				if (!(value >= 1000f) && !(value <= -1000f))
				{
					return $"{value:0.#}";
				}
				return NumberFormat.Abbreviate(value);
			default:
				if (!(value >= 1000f) && !(value <= -1000f))
				{
					return $"{value:0}";
				}
				return NumberFormat.Abbreviate(value);
			}
		}
	}
	public static class StatCatalog
	{
		public static readonly IReadOnlyList<StatDisplayInfo> DisplayOrder = new List<StatDisplayInfo>
		{
			new StatDisplayInfo((StatType)0, "Health", StatFormat.Integer),
			new StatDisplayInfo((StatType)8, "Regeneration", StatFormat.Integer),
			new StatDisplayInfo((StatType)10, "Barrier", StatFormat.Integer),
			new StatDisplayInfo((StatType)17, "Cooldown", StatFormat.Percent),
			new StatDisplayInfo((StatType)1, "Damage", StatFormat.Percent),
			new StatDisplayInfo((StatType)14, "Crit Chance", StatFormat.Percent),
			new StatDisplayInfo((StatType)15, "Crit Damage", StatFormat.Percent),
			new StatDisplayInfo((StatType)20, "Duration", StatFormat.Percent),
			new StatDisplayInfo((StatType)19, "Elites Damage", StatFormat.Percent),
			new StatDisplayInfo((StatType)3, "Speed", StatFormat.Decimal),
			new StatDisplayInfo((StatType)12, "Evasion", StatFormat.Integer),
			new StatDisplayInfo((StatType)25, "Experience Bonus", StatFormat.Percent),
			new StatDisplayInfo((StatType)27, "Lifesteal Chance", StatFormat.Percent),
			new StatDisplayInfo((StatType)33, "Projectiles Count", StatFormat.Integer),
			new StatDisplayInfo((StatType)26, "Armor", StatFormat.Integer),
			new StatDisplayInfo((StatType)16, "Size", StatFormat.Percent),
			new StatDisplayInfo((StatType)23, "Magnet", StatFormat.Integer),
			new StatDisplayInfo((StatType)28, "Jumps", StatFormat.Integer),
			new StatDisplayInfo((StatType)38, "Jump Height", StatFormat.Integer),
			new StatDisplayInfo((StatType)36, "Tower Respawn Time", StatFormat.Integer),
			new StatDisplayInfo((StatType)40, "Altar Charge Speed", StatFormat.Integer),
			new StatDisplayInfo((StatType)24, "Luck", StatFormat.Integer),
			new StatDisplayInfo((StatType)43, "Bonus Chest Frequency", StatFormat.Integer)
		};
	}
	public static class StatTemplate
	{
		public static string Render(string template)
		{
			if (string.IsNullOrEmpty(template))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(template.Length + 32);
			int num = 0;
			while (num < template.Length)
			{
				char c = template[num];
				if (c == '[')
				{
					int num2 = template.IndexOf(']', num + 1);
					if (num2 > num && StatTokens.TryResolve(template.Substring(num + 1, num2 - num - 1), out var value))
					{
						stringBuilder.Append(value);
						num = num2 + 1;
						continue;
					}
				}
				stringBuilder.Append(c);
				num++;
			}
			return stringBuilder.ToString();
		}
	}
	public static class StatTokens
	{
		private static readonly Dictionary<string, Func<string>> Tokens = new Dictionary<string, Func<string>>(StringComparer.OrdinalIgnoreCase);

		private static bool _builtinsRegistered;

		public static bool ColorizeValues = true;

		private const string DamageColor = "#FF6B57";

		private const string HealColor = "#7CE07C";

		private const string UtilityColor = "#6FD3E0";

		private const string ScoreColor = "#E6C478";

		private const string WarnColor = "#F0D060";

		private static string Colorize(string hex, string value)
		{
			if (!ColorizeValues)
			{
				return value;
			}
			return "<color=" + hex + ">" + value + "</color>";
		}

		private static string CategoryColorFor(StatType statType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected I4, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Invalid comparison between Unknown and I4
			switch ((int)statType)
			{
			default:
				if ((int)statType == 19)
				{
					goto case 1;
				}
				if (statType - 26 > 1)
				{
					break;
				}
				goto case 0;
			case 1:
			case 2:
			case 7:
			case 14:
			case 15:
				return "#FF6B57";
			case 0:
			case 8:
			case 10:
			case 11:
				return "#7CE07C";
			case 3:
			case 4:
			case 5:
			case 6:
			case 9:
			case 12:
			case 13:
				break;
			}
			return "#6FD3E0";
		}

		private static string HealthColorFor(float fraction01)
		{
			if (!(fraction01 >= 0.6f))
			{
				if (!(fraction01 >= 0.3f))
				{
					return "#FF6B57";
				}
				return "#F0D060";
			}
			return "#7CE07C";
		}

		public static void Register(string tokenName, Func<string> resolver)
		{
			if (!string.IsNullOrEmpty(tokenName) && resolver != null)
			{
				Tokens[tokenName] = resolver;
			}
		}

		public static bool TryResolve(string tokenName, out string value)
		{
			EnsureBuiltinsRegistered();
			if (Tokens.TryGetValue(tokenName, out var value2))
			{
				try
				{
					value = value2() ?? "N/A";
					return true;
				}
				catch
				{
					value = "N/A";
					return true;
				}
			}
			value = null;
			return false;
		}

		public static IEnumerable<string> KnownTokenNames()
		{
			EnsureBuiltinsRegistered();
			return Tokens.Keys;
		}

		private static void EnsureBuiltinsRegistered()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (_builtinsRegistered)
			{
				return;
			}
			_builtinsRegistered = true;
			foreach (StatDisplayInfo item in StatCatalog.DisplayOrder)
			{
				StatType statType = item.StatType;
				StatDisplayInfo captured = item;
				Register(((object)Unsafe.As<StatType, StatType>(ref statType)/*cast due to .constrained prefix*/).ToString(), () => (!LocalPlayerStats.TryGetValue(statType, out var value)) ? "N/A" : Colorize(CategoryColorFor(statType), captured.FormatValue(value)));
			}
			Register("kills", () => Colorize("#E6C478", LocalPlayerProgress.GetKills().ToString()));
			Register("totalDamage", () => Colorize("#FF6B57", NumberFormat.Abbreviate(LocalPlayerProgress.GetTotalDamage())));
			Register("weaponCount", () => LocalPlayerProgress.GetWeaponLevels().Count.ToString());
			Register("passiveCount", () => LocalPlayerProgress.GetPassiveLevels().Count.ToString());
			Register("itemCount", () => LocalPlayerProgress.GetItemLevels().Count.ToString());
			Register("weapons", () => JoinPresetLevels(LocalPlayerProgress.GetWeaponLevels()));
			Register("passives", () => JoinPresetLevels(LocalPlayerProgress.GetPassiveLevels()));
			Register("items", () => JoinPresetLevels(LocalPlayerProgress.GetItemLevels()));
			Register("questStep", () => (!MatchObjective.TryGetCurrentStep(out var step)) ? "N/A" : DescribeQuestStep(step));
			Register("weaponStats", BuildWeaponStatsBlock);
			Register("dps", () => Colorize("#FF6B57", NumberFormat.Abbreviate(CombatMeter.GetDps())));
			Register("kpm", () => Colorize("#E6C478", $"{CombatMeter.GetKillsPerMinute():0.#}"));
			Register("comboDamage", () => Colorize("#FF6B57", NumberFormat.Abbreviate(CombatMeter.GetCurrentComboDamage())));
			Register("timeSinceLastHit", delegate
			{
				float timeSinceLastHit = CombatMeter.GetTimeSinceLastHit();
				return (!(timeSinceLastHit < 0f)) ? Colorize("#6FD3E0", $"{timeSinceLastHit:0.0}s") : "N/A";
			});
			Register("currentHealth", () => (!LocalPlayerStats.TryGetCurrentHealth(out var _, out var max)) ? "N/A" : Colorize(HealthColorFor((max > 0f) ? (current2 / max) : 0f), NumberFormat.Abbreviate(current2)));
			Register("maxHealthCurrent", () => (!LocalPlayerStats.TryGetCurrentHealth(out current2, out max)) ? "N/A" : NumberFormat.Abbreviate(max));
			Register("healthFraction", delegate
			{
				float healthFraction = LocalPlayerStats.GetHealthFraction();
				return Colorize(HealthColorFor(healthFraction), $"{healthFraction * 100f:0}%");
			});
			Register("healthBar", delegate
			{
				float healthFraction = LocalPlayerStats.GetHealthFraction();
				return Colorize(HealthColorFor(healthFraction), BuildBar(healthFraction, 20));
			});
			Register("matchTime", () => Colorize("#6FD3E0", MatchTimer.GetFormattedTime()));
		}

		private static string BuildBar(float fraction01, int length)
		{
			fraction01 = ((fraction01 < 0f) ? 0f : ((fraction01 > 1f) ? 1f : fraction01));
			int num = (int)(fraction01 * (float)length + 0.5f);
			return new string('#', num) + new string('-', length - num);
		}

		private static string DescribeQuestStep(QuestStep step)
		{
			return step switch
			{
				QuestStep.FindBossLair => "Find the boss's lair", 
				QuestStep.SummonBoss => "Summon the boss", 
				QuestStep.DefeatBoss => "Defeat the boss", 
				QuestStep.ActivateSvetoch => "Activate the Svetoch", 
				QuestStep.Completed => "Completed", 
				_ => step.ToString(), 
			};
		}

		private static string BuildWeaponStatsBlock()
		{
			List<WeaponCombatEntry> entries = WeaponCombatMeter.GetEntries();
			if (entries.Count == 0)
			{
				return "None";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < entries.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append('\n');
				}
				WeaponCombatEntry weaponCombatEntry = entries[i];
				stringBuilder.Append(weaponCombatEntry.Preset.DisplayName).Append("  ").Append(Colorize("#FF6B57", "DPS: " + NumberFormat.Abbreviate(weaponCombatEntry.Dps)))
					.Append("  ")
					.Append(Colorize("#E6C478", $"Kills: {weaponCombatEntry.Kills}"));
			}
			return stringBuilder.ToString();
		}

		private static string JoinPresetLevels(List<PresetLevelEntry> entries)
		{
			if (entries.Count == 0)
			{
				return "None";
			}
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < entries.Count; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append(", ");
				}
				stringBuilder.Append(entries[i].Preset.DisplayName).Append(" Lv").Append(entries[i].Level);
			}
			return stringBuilder.ToString();
		}
	}
	public static class UiFont
	{
		private static readonly ManualLogSource Log = Logger.CreateLogSource("SineusModding.Api.UiFont");

		private static readonly string[] LinuxFallbacks = new string[6] { "Noto Sans", "DejaVu Sans", "Liberation Sans", "Ubuntu", "Cantarell", "FreeSans" };

		private static HashSet<string> installedFontNames;

		public static Font CreateSafe(string[] preferredNames, int fontSize)
		{
			try
			{
				EnsureInstalledFontNamesLoaded();
				string text = preferredNames.FirstOrDefault(installedFontNames.Contains) ?? LinuxFallbacks.FirstOrDefault(installedFontNames.Contains);
				if (text == null)
				{
					Log.LogWarning((object)"No usable OS font found among preferred or fallback names; using Unity's built-in GUI font.");
					return null;
				}
				Font val = Font.CreateDynamicFontFromOSFont(text, fontSize);
				if ((Object)(object)val != (Object)null)
				{
					((Object)val).hideFlags = (HideFlags)61;
				}
				return val;
			}
			catch (Exception arg)
			{
				Log.LogWarning((object)$"Failed to create OS font, falling back to Unity's built-in GUI font: {arg}");
				return null;
			}
		}

		private static void EnsureInstalledFontNamesLoaded()
		{
			if (installedFontNames != null)
			{
				return;
			}
			try
			{
				installedFontNames = new HashSet<string>(Font.GetOSInstalledFontNames(), StringComparer.OrdinalIgnoreCase);
			}
			catch (Exception arg)
			{
				Log.LogWarning((object)$"Could not enumerate OS installed fonts: {arg}");
				installedFontNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			}
		}
	}
	public enum UpdateCheckStatus
	{
		NotChecked,
		Checking,
		UpToDate,
		UpdateAvailable,
		Failed
	}
	public readonly struct UpdateCheckResult
	{
		public readonly UpdateCheckStatus Status;

		public readonly string LatestVersion;

		public readonly string ReleaseUrl;

		public UpdateCheckResult(UpdateCheckStatus status, string latestVersion, string releaseUrl)
		{
			Status = status;
			LatestVersion = latestVersion;
			ReleaseUrl = releaseUrl;
		}
	}
	public static class UpdateChecker
	{
		private static readonly ManualLogSource Log = Logger.CreateLogSource("SineusModding.Api.UpdateChecker");

		private static readonly Regex VersionPattern = new Regex("\\d+(\\.\\d+)*", RegexOptions.Compiled);

		public static void CheckAsync(MonoBehaviour host, string githubOwner, string githubRepo, string currentVersion, Action<UpdateCheckResult> onResult)
		{
			if ((Object)(object)host == (Object)null || string.IsNullOrEmpty(githubOwner) || string.IsNullOrEmpty(githubRepo))
			{
				onResult?.Invoke(new UpdateCheckResult(UpdateCheckStatus.Failed, null, null));
			}
			else
			{
				host.StartCoroutine(CheckCoroutine(githubOwner, githubRepo, currentVersion, onResult));
			}
		}

		private static IEnumerator CheckCoroutine(string owner, string repo, string currentVersion, Action<UpdateCheckResult> onResult)
		{
			string text = "https://api.github.com/repos/" + owner + "/" + repo + "/releases/latest";
			UnityWebRequest request = UnityWebRequest.Get(text);
			try
			{
				request.SetRequestHeader("Accept", "application/vnd.github+json");
				request.SetRequestHeader("User-Agent", repo + "-UpdateChecker");
				request.timeout = 10;
				yield return request.SendWebRequest();
				if ((int)request.result != 1)
				{
					Log.LogInfo((object)("[" + repo + "] Update check failed: " + request.error));
					onResult?.Invoke(new UpdateCheckResult(UpdateCheckStatus.Failed, null, null));
					yield break;
				}
				string text2 = ExtractJsonStringField(request.downloadHandler.text, "tag_name");
				string releaseUrl = ExtractJsonStringField(request.downloadHandler.text, "html_url");
				if (string.IsNullOrEmpty(text2))
				{
					Log.LogInfo((object)("[" + repo + "] Update check: response had no tag_name (repo may have no releases yet)."));
					onResult?.Invoke(new UpdateCheckResult(UpdateCheckStatus.Failed, null, null));
					yield break;
				}
				bool flag = IsNewerVersion(currentVersion, text2);
				if (flag)
				{
					Log.LogInfo((object)("[" + repo + "] Update available: " + currentVersion + " -> " + text2));
				}
				onResult?.Invoke(new UpdateCheckResult(flag ? UpdateCheckStatus.UpdateAvailable : UpdateCheckStatus.UpToDate, text2, releaseUrl));
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public static bool IsNewerVersion(string currentVersion, string latestVersion)
		{
			Match match = VersionPattern.Match(currentVersion ?? string.Empty);
			Match match2 = VersionPattern.Match(latestVersion ?? string.Empty);
			if (!match.Success || !match2.Success)
			{
				return false;
			}
			int[] array = ParseSegments(match.Value);
			int[] array2 = ParseSegments(match2.Value);
			int num = Mathf.Max(array.Length, array2.Length);
			for (int i = 0; i < num; i++)
			{
				int num2 = ((i < array.Length) ? array[i] : 0);
				int num3 = ((i < array2.Length) ? array2[i] : 0);
				if (num3 != num2)
				{
					return num3 > num2;
				}
			}
			return false;
		}

		private static int[] ParseSegments(string dotted)
		{
			string[] array = dotted.Split(new char[1] { '.' });
			int[] array2 = new int[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				int.TryParse(array[i], out array2[i]);
			}
			return array2;
		}

		private static string ExtractJsonStringField(string json, string fieldName)
		{
			if (string.IsNullOrEmpty(json))
			{
				return null;
			}
			Match match = new Regex("\"" + Regex.Escape(fieldName) + "\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"").Match(json);
			if (!match.Success)
			{
				return null;
			}
			return Regex.Unescape(match.Groups[1].Value);
		}
	}
	public sealed class UpdateNotice
	{
		private const int WindowId = 887422;

		private readonly string _modName;

		private bool _visible;

		private string _latestVersion;

		private string _releaseUrl;

		private Rect _rect;

		private GUIStyle _windowStyle;

		private GUIStyle _textStyle;

		private GUIStyle _buttonStyle;

		private bool _stylesReady;

		private Texture2D _panelTexture;

		private Font _uiFont;

		public UpdateNotice(string modName)
		{
			_modName = modName;
		}

		public void Show(string latestVersion, string releaseUrl)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			_latestVersion = latestVersion;
			_releaseUrl = releaseUrl;
			_visible = true;
			_rect = new Rect(20f, 20f, 340f, 10f);
		}

		public void Draw()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0061: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (_visible)
			{
				EnsureStyles();
				_rect = ClampToScreen(_rect);
				_rect = GUILayout.Window(887422, _rect, new WindowFunction(DrawWindow), string.Empty, _windowStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(((Rect)(ref _rect)).width) });
			}
		}

		private void DrawWindow(int windowId)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Label("<color=#E6C478><b>" + _modName + "</b></color> <color=#7CE07C>update available</color>", _textStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("<color=#9FB4BA>New version:</color> <color=#FFFFFF>" + _latestVersion + "</color>", _textStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("<color=#9FB4BA>Get it at:</color>\n<color=#6FD3E0>" + _releaseUrl + "</color>", _textStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Copy link", _buttonStyle, Array.Empty<GUILayoutOption>()))
			{
				GUIUtility.systemCopyBuffer = _releaseUrl;
			}
			if (GUILayout.Button("Dismiss", _buttonStyle, Array.Empty<GUILayoutOption>()))
			{
				_visible = false;
			}
			GUILayout.EndHorizontal();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 24f));
		}

		private static Rect ClampToScreen(Rect rect)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(((Rect)(ref rect)).x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref rect)).width));
			float num2 = Mathf.Clamp(((Rect)(ref rect)).y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref rect)).height));
			return new Rect(num, num2, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height);
		}

		private void EnsureStyles()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_0081: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_00f7: 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_0119: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			//IL_0197: Expected O, but got Unknown
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Expected O, but got Unknown
			if (!_stylesReady || !((Object)(object)_panelTexture != (Object)null) || !((Object)(object)_uiFont != (Object)null))
			{
				_uiFont = UiFont.CreateSafe(new string[3] { "Segoe UI", "Segoe UI Semibold", "Arial" }, 13);
				Color fill = Color32.op_Implicit(new Color32((byte)10, (byte)26, (byte)34, (byte)235));
				Color border = Color32.op_Implicit(new Color32((byte)198, (byte)158, (byte)74, byte.MaxValue));
				Color textColor = Color32.op_Implicit(new Color32((byte)224, (byte)230, (byte)232, byte.MaxValue));
				_panelTexture = MakeBorderedTexture(fill, border);
				GUIStyle val = new GUIStyle(GUI.skin.window)
				{
					font = _uiFont,
					border = new RectOffset(2, 2, 2, 2),
					overflow = new RectOffset(0, 0, 0, 0),
					margin = new RectOffset(0, 0, 0, 0)
				};
				val.normal.background = _panelTexture;
				val.onNormal.background = _panelTexture;
				val.hover.background = _panelTexture;
				val.onHover.background = _panelTexture;
				val.active.background = _panelTexture;
				val.onActive.background = _panelTexture;
				val.focused.background = _panelTexture;
				val.onFocused.background = _panelTexture;
				val.padding = new RectOffset(10, 10, 10, 10);
				_windowStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					font = _uiFont,
					fontSize = 13,
					richText = true,
					wordWrap = true
				};
				val2.normal.textColor = textColor;
				_textStyle = val2;
				_buttonStyle = new GUIStyle(GUI.skin.button)
				{
					font = _uiFont,
					fontSize = 12
				};
				_stylesReady = true;
			}
		}

		private static Texture2D MakeBorderedTexture(Color fill, Color border)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(12, 12, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				hideFlags = (HideFlags)61
			};
			for (int i = 0; i < 12; i++)
			{
				for (int j = 0; j < 12; j++)
				{
					bool flag = j < 2 || i < 2 || j >= 10 || i >= 10;
					val.SetPixel(j, i, flag ? border : fill);
				}
			}
			val.Apply();
			return val;
		}
	}
	public readonly struct WeaponCombatEntry
	{
		public readonly string SourceId;

		public readonly PresetInfo Preset;

		public readonly float Dps;

		public readonly int Kills;

		public readonly float TotalDamage;

		public WeaponCombatEntry(string sourceId, PresetInfo preset, float dps, int kills, float totalDamage)
		{
			SourceId = sourceId;
			Preset = preset;
			Dps = dps;
			Kills = kills;
			TotalDamage = totalDamage;
		}
	}
	public static class WeaponCombatMeter
	{
		private readonly struct Sample
		{
			public readonly float Time;

			public readonly float CumulativeDamage;

			public Sample(float time, float cumulativeDamage)
			{
				Time = time;
				CumulativeDamage = cumulativeDamage;
			}
		}

		private class SourceState
		{
			public readonly List<Sample> Samples = new List<Sample>();

			public float LastCumulativeDamage;

			public int Kills;
		}

		private const float DpsWindowSeconds = 10f;

		private const float SampleInterval = 0.1f;

		private static readonly Dictionary<string, SourceState> Sources = new Dictionary<string, SourceState>(StringComparer.Ordinal);

		private static readonly HashSet<string> LoggedSources = new HashSet<string>(StringComparer.Ordinal);

		private static readonly ManualLogSource Log = Logger.CreateLogSource("SineusModding.Api.WeaponCombatMeter");

		private static float lastSampleTime = -999f;

		private static float lastTotalDamageSeen;

		private static int lastTotalKillsSeen;

		public static void Tick()
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - lastSampleTime < 0.1f)
			{
				return;
			}
			lastSampleTime = unscaledTime;
			List<DamageSourceEntry> damageBySource = LocalPlayerProgress.GetDamageBySource();
			int kills = LocalPlayerProgress.GetKills();
			float num = 0f;
			foreach (DamageSourceEntry item in damageBySource)
			{
				num += item.Damage;
			}
			if (num < lastTotalDamageSeen || kills < lastTotalKillsSeen)
			{
				Reset();
			}
			lastTotalDamageSeen = num;
			int num2 = kills - lastTotalKillsSeen;
			lastTotalKillsSeen = kills;
			string text = null;
			float num3 = 0f;
			foreach (DamageSourceEntry item2 in damageBySource)
			{
				LogSourceOnceIfNew(item2.SourceName);
				SourceState orCreate = GetOrCreate(item2.SourceName);
				float num4 = item2.Damage - orCreate.LastCumulativeDamage;
				orCreate.LastCumulativeDamage = item2.Damage;
				orCreate.Samples.Add(new Sample(unscaledTime, item2.Damage));
				TrimSamples(orCreate, unscaledTime);
				if (num4 > num3)
				{
					num3 = num4;
					text = item2.SourceName;
				}
			}
			if (num2 > 0 && text != null)
			{
				Sources[text].Kills += num2;
			}
		}

		public static List<WeaponCombatEntry> GetEntries()
		{
			float unscaledTime = Time.unscaledTime;
			List<PresetLevelEntry> weaponLevels = LocalPlayerProgress.GetWeaponLevels();
			SourceState[] array = new SourceState[weaponLevels.Count];
			List<int> list = new List<int>();
			for (int i = 0; i < weaponLevels.Count; i++)
			{
				if (Sources.TryGetValue(weaponLevels[i].Preset.SystemId, out var value))
				{
					array[i] = value;
				}
				else
				{
					list.Add(i);
				}
			}
			if (list.Count == 1 && LocalPlayerStats.TryGetLocalUnitName(out var name) && Sources.TryGetValue(name, out var value2))
			{
				array[list[0]] = value2;
			}
			else if (list.Count > 0)
			{
				LogUnmatchedOnce(weaponLevels, list);
			}
			List<WeaponCombatEntry> list2 = new List<WeaponCombatEntry>(weaponLevels.Count);
			for (int j = 0; j < weaponLevels.Count; j++)
			{
				float dps = 0f;
				int kills = 0;
				float totalDamage = 0f;
				SourceState sourceState = array[j];
				if (sourceState != null)
				{
					TrimSamples(sourceState, unscaledTime);
					dps = GetDps(sourceState, unscaledTime);
					kills = sourceState.Kills;
					totalDamage = sourceState.LastCumulativeDamage;
				}
				list2.Add(new WeaponCombatEntry(weaponLevels[j].Preset.SystemId, weaponLevels[j].Preset, dps, kills, totalDamage));
			}
			list2.Sort(delegate(WeaponCombatEntry a, WeaponCombatEntry b)
			{
				float totalDamage2 = b.TotalDamage;
				return totalDamage2.CompareTo(a.TotalDamage);
			});
			return list2;
		}

		private static void LogSourceOnceIfNew(string sourceName)
		{
			if (LoggedSources.Add(sourceName))
			{
				string name;
				string text = (LocalPlayerStats.TryGetLocalUnitName(out name) ? ("\"" + name + "\"") : "N/A");
				Log.LogInfo((object)("[WeaponCombatMeter] new damage source: \"" + sourceName + "\" (local hero unit name: " + text + ")"));
			}
		}

		private static void LogUnmatchedOnce(List<PresetLevelEntry> weapons, List<int> unmatched)
		{
			List<string> list = new List<string>();
			foreach (int item2 in unmatched)
			{
				list.Add(weapons[item2].Preset.DisplayName);
			}
			string item = "unmatched:" + string.Join(",", list);
			if (LoggedSources.Add(item))
			{
				string name;
				bool flag = LocalPlayerStats.TryGetLocalUnitName(out name);
				bool flag2 = flag && Sources.ContainsKey(name);
				Log.LogInfo((object)(string.Format("[WeaponCombatMeter] {0} equipped weapon(s) with no damage-source match: [{1}]. ", unmatched.Count, string.Join(", ", list)) + string.Format("Hero unit name: {0}, has its own damage entry: {1}. ", flag ? ("\"" + name + "\"") : "N/A", flag2) + "Known damage sources: [" + string.Join(", ", Sources.Keys) + "]"));
			}
		}

		private static float GetDps(SourceState state, float now)
		{
			if (state.Samples.Count < 2)
			{
				return 0f;
			}
			Sample sample = state.Samples[0];
			Sample sample2 = state.Samples[state.Samples.Count - 1];
			float num = sample2.Time - sample.Time;
			if (num <= 0.01f)
			{
				return 0f;
			}
			return Mathf.Max(0f, (sample2.CumulativeDamage - sample.CumulativeDamage) / num);
		}

		private static void TrimSamples(SourceState state, float now)
		{
			float num = now - 10f;
			int i;
			for (i = 0; i < state.Samples.Count && state.Samples[i].Time < num; i++)
			{
			}
			if (i > 0)
			{
				state.Samples.RemoveRange(0, i);
			}
		}

		private static SourceState GetOrCreate(string sourceId)
		{
			if (!Sources.TryGetValue(sourceId, out var value))
			{
				value = new SourceState();
				Sources[sourceId] = value;
			}
			return value;
		}

		private static void Reset()
		{
			Sources.Clear();
			lastTotalDamageSeen = 0f;
			lastTotalKillsSeen = 0;
		}
	}
}