Decompiled source of EpicLoot ProgressionFix v0.1.54

plugins/EpicLootProgressionFix.dll

Decompiled 8 minutes ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Common;
using EpicLoot;
using EpicLoot.Adventure;
using EpicLoot.Biomes;
using EpicLoot.Crafting;
using EpicLoot.CraftingV2;
using EpicLoot.Data;
using EpicLoot.GatedItemType;
using EpicLoot.Magic.MagicItemEffects;
using EpicLoot.MagicItemEffects;
using EpicLoot.MagicItemEffects.Shards;
using EpicLoot.src.Magic.MagicItemEffects.Helpers;
using EpicLoot_UnityLib;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.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 EpicLootProgressionFix
{
	internal static class AchievementDiscord
	{
		private static readonly HashSet<string> ObservedUnlocks = new HashSet<string>();

		private static FieldInfo discordInstance;

		private static MethodInfo sendMessage;

		private static object chat;

		private static object defaultRoute;

		private static ManualLogSource logger;

		[ThreadStatic]
		private static int suppressedUnlocks;

		internal static void Initialize(Harmony harmony, ManualLogSource log)
		{
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_0170: Expected O, but got Unknown
			//IL_0170: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("RustyMods.DiscordBot", out var value))
			{
				logger = log;
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				Type type = assembly.GetType("DiscordBot.Discord");
				Type type2 = assembly.GetType("DiscordBot.Webhook");
				Type type3 = assembly.GetType("DiscordBot.WebhookRoute");
				if (type == null || type2 == null || type3 == null)
				{
					throw new InvalidOperationException("DiscordBot achievement relay API changed.");
				}
				discordInstance = AccessTools.Field(type, "instance");
				sendMessage = AccessTools.Method(type, "SendMessage", new Type[5]
				{
					type2,
					typeof(string),
					typeof(string),
					typeof(List<string>),
					type3
				}, (Type[])null);
				if (discordInstance == null || sendMessage == null)
				{
					throw new InvalidOperationException("Achievement relay API changed.");
				}
				EnglishText.Initialize();
				chat = Enum.Parse(type2, "Chat");
				defaultRoute = Enum.Parse(type3, "Default");
				harmony.Patch((MethodBase)AccessTools.Method(typeof(Achievements), "AchievementEvent", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AchievementDiscord), "BeforeUnlock", (Type[])null), new HarmonyMethod(typeof(AchievementDiscord), "AfterUnlock", (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDiscord), "AfterUnlockTree", (Type[])null), (HarmonyMethod)null);
			}
		}

		private static void BeforeUnlock(bool synchronize, out int __state)
		{
			__state = suppressedUnlocks;
			if (!synchronize)
			{
				suppressedUnlocks++;
			}
		}

		private static void AfterUnlockTree(int __state)
		{
			suppressedUnlocks = __state;
		}

		private static void AfterUnlock(Achievement ach)
		{
			if ((Object)(object)ach == (Object)null || !ObservedUnlocks.Add(ach.m_id) || suppressedUnlocks != 0 || !Plugin.DiscordAchievements.Value || !Plugin.Ready)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			ZRpc val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerRPC() : null);
			if ((Object)(object)localPlayer == (Object)null || val == null || !val.IsConnected())
			{
				return;
			}
			try
			{
				object value = discordInstance.GetValue(null);
				if (value == null)
				{
					throw new InvalidOperationException("DiscordBot is not ready to relay the achievement.");
				}
				string text = English(ach.m_name);
				string text2 = English(ach.m_description);
				if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2))
				{
					throw new InvalidOperationException("Achievement " + ach.m_id + " has no English name or requirement description.");
				}
				string text3 = PlainText(localPlayer.GetPlayerName());
				string text4 = text3 + " earned the achievement \"" + text + "\" [" + text2 + "]";
				sendMessage.Invoke(value, new object[5]
				{
					chat,
					text3,
					DiscordSystemMessages.Box(text4),
					null,
					defaultRoute
				});
			}
			catch (Exception ex)
			{
				logger.LogError((object)("Could not announce achievement " + ach.m_id + ": " + ex.GetBaseException().Message));
			}
		}

		private static string English(string text)
		{
			if (!EnglishText.TryTranslate(text, out var english))
			{
				throw new InvalidOperationException("Missing English achievement text: " + english);
			}
			return PlainText(english);
		}

		private static string PlainText(string text)
		{
			text = Regex.Replace(text ?? "", "<[^>]*>", "").Replace("\\n", " ");
			return Regex.Replace(text, "\\s+", " ").Trim();
		}
	}
	[HarmonyPatch(typeof(SE_CustomFinder), "UpdateStatusEffect")]
	internal static class AndvaranautTracking
	{
		private enum TargetFix
		{
			Circle,
			Located
		}

		private const float ScanInterval = 1f;

		private const float PingInterval = 5f;

		private const float TurnPingGap = 1.5f;

		private const float MinimumApproach = 2f;

		private const float TeleportDistance = 200f;

		private static readonly FieldRef<SE_Finder, Beacon> RingBeacon = AccessTools.FieldRefAccess<SE_Finder, Beacon>("m_beacon");

		private static readonly FieldRef<List<Beacon>> Beacons = AccessTools.StaticFieldRefAccess<List<Beacon>>(AccessTools.Field(typeof(Beacon), "m_instances"));

		private static SE_CustomFinder finder;

		private static string targetKey;

		private static Vector3 targetPosition;

		private static TargetFix targetFix;

		private static bool beyondSearchRadius;

		private static bool pingedWhileFacing;

		private static float scanTimer;

		private static float checkTimer;

		private static float sincePing;

		private static Vector3 checkPosition;

		private static void Postfix(SE_CustomFinder __instance, float dt)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)((StatusEffect)__instance).m_character != (Object)(object)localPlayer)
			{
				return;
			}
			List<Type> requiredComponentTypes = __instance.RequiredComponentTypes;
			if (requiredComponentTypes == null || !requiredComponentTypes.Contains(typeof(TreasureMapChest)))
			{
				return;
			}
			if ((Object)(object)__instance != (Object)(object)finder)
			{
				finder = __instance;
				targetKey = null;
				scanTimer = 1f;
			}
			sincePing += dt;
			if ((Object)(object)RingBeacon.Invoke((SE_Finder)(object)__instance) != (Object)null)
			{
				targetKey = null;
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			bool flag = false;
			scanTimer += dt;
			if (scanTimer >= 1f)
			{
				scanTimer = 0f;
				string text = targetKey;
				TargetFix targetFix = AndvaranautTracking.targetFix;
				FindTarget(localPlayer, position);
				flag = targetKey != text || AndvaranautTracking.targetFix != targetFix;
			}
			if (targetKey != null)
			{
				float num = Utils.DistanceXZ(position, targetPosition);
				bool flag2 = num > Plugin.AndvaranautSearchRadius.Value;
				if (flag || flag2 != beyondSearchRadius)
				{
					beyondSearchRadius = flag2;
					pingedWhileFacing = false;
					checkTimer = 0f;
					checkPosition = position;
				}
				if (beyondSearchRadius)
				{
					PingWhenFacing((SE_Finder)(object)__instance, localPlayer, position);
				}
				else
				{
					PingWhenApproaching((SE_Finder)(object)__instance, localPlayer, position, num, dt);
				}
			}
		}

		private static void PingWhenFacing(SE_Finder ring, Player player, Vector3 position)
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_004c: 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)
			Vector3 lookDir = ((Character)player).GetLookDir();
			Vector3 val = targetPosition - position;
			lookDir.y = 0f;
			val.y = 0f;
			float value = Plugin.AndvaranautFacingAngle.Value;
			if (value <= 0f || ((Vector3)(ref lookDir)).sqrMagnitude < 0.0001f || Vector3.Angle(lookDir, val) > value)
			{
				pingedWhileFacing = false;
			}
			else if (!(sincePing < (pingedWhileFacing ? 5f : 1.5f)))
			{
				Ping(ring, player);
				pingedWhileFacing = true;
			}
		}

		private static void PingWhenApproaching(SE_Finder ring, Player player, Vector3 position, float distance, float dt)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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)
			checkTimer += dt;
			if (!(checkTimer < 5f))
			{
				checkTimer = 0f;
				float num = Utils.DistanceXZ(checkPosition, position);
				float num2 = Utils.DistanceXZ(checkPosition, targetPosition) - distance;
				checkPosition = position;
				if (num <= 200f && num2 >= Mathf.Max(2f, num / 2f))
				{
					Ping(ring, player);
				}
			}
		}

		private static void Ping(SE_Finder ring, Player player)
		{
			//IL_000e: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)player).transform;
			ring.m_pingEffectFar.Create(transform.position, transform.rotation, transform, 1f, -1, ((Character)player).GetZDOID());
			sincePing = 0f;
		}

		private static void FindTarget(Player player, Vector3 position)
		{
			//IL_0096: 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_00a9: 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_0072: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			targetKey = null;
			float nearest = ((Plugin.AndvaranautMaxRange.Value > 0f) ? Plugin.AndvaranautMaxRange.Value : float.MaxValue);
			AdventureSaveData adventureSaveData = PlayerExtensions_Adventure.GetAdventureSaveData(player);
			long playerID = player.GetPlayerID();
			foreach (TreasureMapChestInfo unfoundTreasureChest in adventureSaveData.GetUnfoundTreasureChests())
			{
				Vector3 located;
				TargetFix targetFix = (LocateChest(unfoundTreasureChest, playerID, out located) ? TargetFix.Located : TargetFix.Circle);
				if (targetFix == TargetFix.Circle)
				{
					located = SerializableVector3.op_Implicit(unfoundTreasureChest.Position) + SerializableVector3.op_Implicit(unfoundTreasureChest.MinimapCircleOffset);
				}
				Consider($"treasure:{unfoundTreasureChest.Interval}:{unfoundTreasureChest.Biome}", located, targetFix, position, ref nearest);
			}
			foreach (BountyInfo inProgressBounty in adventureSaveData.GetInProgressBounties())
			{
				Vector3 located2;
				TargetFix targetFix2 = (LocateBounty(inProgressBounty.ID, position, out located2) ? TargetFix.Located : TargetFix.Circle);
				if (targetFix2 == TargetFix.Circle)
				{
					located2 = SerializableVector3.op_Implicit(inProgressBounty.Position) + SerializableVector3.op_Implicit(inProgressBounty.MinimapCircleOffset);
				}
				Consider(inProgressBounty.ID, located2, targetFix2, position, ref nearest);
			}
		}

		private static void Consider(string key, Vector3 candidate, TargetFix fix, Vector3 position, ref float nearest)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			float num = Utils.DistanceXZ(position, candidate);
			if (!(num >= nearest))
			{
				nearest = num;
				targetKey = key;
				targetPosition = candidate;
				targetFix = fix;
			}
		}

		private static bool LocateChest(TreasureMapChestInfo map, long playerId, out Vector3 located)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			foreach (Beacon item in Beacons.Invoke())
			{
				TreasureMapChest val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<TreasureMapChest>() : null);
				ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null);
				if (!((Object)(object)val2 == (Object)null) && val2.IsValid() && val.Interval == map.Interval && val.Biome == map.Biome && val2.GetZDO().GetLong("creator", 0L) == playerId)
				{
					located = ((Component)val).transform.position;
					return true;
				}
			}
			located = default(Vector3);
			return false;
		}

		private static bool LocateBounty(string bountyId, Vector3 position, out Vector3 located)
		{
			//IL_0007: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			float num = float.MaxValue;
			located = default(Vector3);
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				ZNetView val = (((Object)(object)allCharacter != (Object)null && !allCharacter.IsDead()) ? ((Component)allCharacter).GetComponent<ZNetView>() : null);
				if (!((Object)(object)val == (Object)null) && val.IsValid() && !(val.GetZDO().GetString("BountyID", "") != bountyId))
				{
					float num2 = Utils.DistanceXZ(position, ((Component)allCharacter).transform.position);
					if (!(num2 >= num))
					{
						num = num2;
						located = ((Component)allCharacter).transform.position;
					}
				}
			}
			return num < float.MaxValue;
		}
	}
	[HarmonyPatch]
	internal static class KeepBountyBeacons
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(BountyTarget).Assembly.GetType("EpicLoot.Adventure.BountyTargetComponent+Character_OnDamaged_Patch"), "Postfix", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("EpicLoot's bounty beacon removal moved.");
		}

		private static bool Prefix()
		{
			return false;
		}
	}
	[HarmonyPatch(typeof(AutoMeads), "OnIncomingHit")]
	internal static class AutomaticMeadPrediction
	{
		private static bool Prefix()
		{
			return false;
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class AutomaticMeadConsumption
	{
		private static void Prefix(Character __instance, out float __state)
		{
			__state = (((Object)(object)__instance == (Object)(object)Player.m_localPlayer) ? __instance.GetHealth() : 0f);
		}

		private static void Postfix(Character __instance, float __state)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			float health = ((Character)val).GetHealth();
			if (health <= 0f || health >= __state || ((Character)val).IsDead() || !PlayerExtensions.HasActiveMagicEffect(val, MagicEffectType.AutoMead) || !ModifyWithLowHealth.PlayerHasLowHealth(val))
			{
				return;
			}
			Inventory inventory = ((Humanoid)val).GetInventory();
			if (inventory == null)
			{
				return;
			}
			SEMan sEMan = ((Character)val).GetSEMan();
			foreach (ItemData item in inventory.GetAllItemsOfType((ItemType)2, false))
			{
				if (AutoMeads.HasHealthRegen(item))
				{
					StatusEffect consumeStatusEffect = item.m_shared.m_consumeStatusEffect;
					if (!sEMan.HaveStatusEffect(consumeStatusEffect.NameHash()) && !sEMan.HaveStatusEffectCategory(consumeStatusEffect.m_category) && ((Humanoid)val).ConsumeItem(inventory, item, false))
					{
						break;
					}
				}
			}
		}
	}
	internal static class BlockAfterArmor
	{
		private static readonly Func<Character, short, WeakSpot> WeakSpotOf = AccessTools.MethodDelegate<Func<Character, short, WeakSpot>>(AccessTools.Method(typeof(Character), "GetWeakSpot", (Type[])null, (Type[])null), (object)null, true);

		private static HitData reducedHit;

		private static DamageModifier reducedHitModifier;

		internal static void Initialize(Harmony harmony)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Humanoid), "BlockAttack", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BlockAfterArmor), "ReduceBeforeBlock", (Type[])null)
			{
				priority = 800
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Character), "RPC_Damage", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BlockAfterArmor), "ReduceOnce", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void ReduceBeforeBlock(Humanoid __instance, HitData hit)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				BlockedHits.ConvertBeforeBlock(val, hit);
				hit.ApplyResistance(((Character)val).GetDamageModifiers(WeakSpotOf((Character)(object)val, hit.m_weakSpot)), ref reducedHitModifier);
				hit.ApplyArmor(((Character)val).GetBodyArmor());
				reducedHit = hit;
			}
		}

		private static void ApplyResistance(HitData hit, DamageModifiers modifiers, out DamageModifier significantModifier)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected I4, but got Unknown
			if (hit == reducedHit)
			{
				significantModifier = (DamageModifier)(int)reducedHitModifier;
			}
			else
			{
				hit.ApplyResistance(modifiers, ref significantModifier);
			}
		}

		private static void ApplyArmor(HitData hit, float armor)
		{
			if (hit == reducedHit)
			{
				reducedHit = null;
			}
			else
			{
				hit.ApplyArmor(armor);
			}
		}

		private static IEnumerable<CodeInstruction> ReduceOnce(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> code = instructions.ToList();
			MethodInfo block = AccessTools.Method(typeof(Character), "BlockAttack", (Type[])null, (Type[])null);
			MethodInfo resistance = AccessTools.Method(typeof(HitData), "ApplyResistance", new Type[2]
			{
				typeof(DamageModifiers),
				typeof(DamageModifier).MakeByRefType()
			}, (Type[])null);
			MethodInfo armor = AccessTools.Method(typeof(HitData), "ApplyArmor", new Type[1] { typeof(float) }, (Type[])null);
			int num = code.FindIndex((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, block));
			List<int> list = (from i in Enumerable.Range(0, code.Count)
				where CodeInstructionExtensions.Calls(code[i], resistance)
				select i).ToList();
			List<int> list2 = (from i in Enumerable.Range(0, code.Count)
				where CodeInstructionExtensions.Calls(code[i], armor)
				select i).ToList();
			if (num < 0 || list.Count != 1 || list2.Count != 2 || list[0] < num || list2[0] < list[0])
			{
				throw new InvalidOperationException("Valheim's hit order changed; expected the block before one resistance and two armor steps.");
			}
			code[list[0]].opcode = OpCodes.Call;
			code[list[0]].operand = AccessTools.Method(typeof(BlockAfterArmor), "ApplyResistance", (Type[])null, (Type[])null);
			foreach (int item in list2)
			{
				code[item].opcode = OpCodes.Call;
				code[item].operand = AccessTools.Method(typeof(BlockAfterArmor), "ApplyArmor", (Type[])null, (Type[])null);
			}
			return code;
		}
	}
	[HarmonyPatch]
	internal static class BlockedHits
	{
		[HarmonyPatch(typeof(AvoidDamageTaken_Character_RPC_Damage_Patch), "ShouldTakeDamage")]
		private static class NoFeintWhileBlocking
		{
			private static bool Prefix(Character __0, HitData hit, ref bool __result)
			{
				if (hit == null || !WillBlock(__0, hit) || !__0.HaveStamina(0f))
				{
					return true;
				}
				__result = true;
				return false;
			}
		}

		internal static readonly Func<Humanoid, ItemData> CurrentBlocker = AccessTools.MethodDelegate<Func<Humanoid, ItemData>>(AccessTools.Method(typeof(Humanoid), "GetCurrentBlocker", (Type[])null, (Type[])null), (object)null, true);

		internal static bool WillBlock(Character character, HitData hit)
		{
			//IL_001b: 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)
			Humanoid val = (Humanoid)(object)((character is Humanoid) ? character : null);
			if (val != null && hit.m_blockable && ((Character)val).IsBlocking() && Vector3.Dot(hit.m_dir, ((Component)val).transform.forward) <= 0f)
			{
				return CurrentBlocker(val) != null;
			}
			return false;
		}

		[HarmonyPatch(typeof(IncomingPhysicalConversion), "ModifyIncoming")]
		[HarmonyPrefix]
		private static bool GeneralConversionOnly(bool IsBlocked)
		{
			return !IsBlocked;
		}

		internal static void ConvertBeforeBlock(Player player, HitData hit)
		{
			if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !WillBlock((Character)(object)player, hit))
			{
				return;
			}
			float totalActiveMagicEffectValue = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFireOnBlock, 0.01f, (ItemData)null);
			float totalActiveMagicEffectValue2 = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFrostOnBlock, 0.01f, (ItemData)null);
			float totalActiveMagicEffectValue3 = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToPoisonOnBlock, 0.01f, (ItemData)null);
			float totalActiveMagicEffectValue4 = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToLightningOnBlock, 0.01f, (ItemData)null);
			float num = totalActiveMagicEffectValue + totalActiveMagicEffectValue2 + totalActiveMagicEffectValue3 + totalActiveMagicEffectValue4;
			float num2 = hit.m_damage.m_blunt + hit.m_damage.m_slash + hit.m_damage.m_pierce;
			if (!(num <= 0f) && !(num2 <= 0f))
			{
				float num3 = 1f - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFire, 0.01f, (ItemData)null) - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFrost, 0.01f, (ItemData)null) - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToPoison, 0.01f, (ItemData)null) - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToLightning, 0.01f, (ItemData)null);
				if (!(num3 <= 0f))
				{
					float num4 = Mathf.Min(1f, num / num3);
					float num5 = num2 * num4 / num;
					hit.m_damage.m_fire += num5 * totalActiveMagicEffectValue;
					hit.m_damage.m_frost += num5 * totalActiveMagicEffectValue2;
					hit.m_damage.m_poison += num5 * totalActiveMagicEffectValue3;
					hit.m_damage.m_lightning += num5 * totalActiveMagicEffectValue4;
					hit.m_damage.m_blunt *= 1f - num4;
					hit.m_damage.m_slash *= 1f - num4;
					hit.m_damage.m_pierce *= 1f - num4;
				}
			}
		}
	}
	internal static class BonusHits
	{
		[HarmonyPatch]
		private static class StrikeMultipliers
		{
			internal static readonly ConditionalWeakTable<HitData, StrongBox<float>> Factors = new ConditionalWeakTable<HitData, StrongBox<float>>();

			private static IEnumerable<MethodBase> TargetMethods()
			{
				return Required(AccessTools.Method(typeof(ChanceToCritOnHit), "ModifyOutgoingHit", (Type[])null, (Type[])null), AccessTools.Method(typeof(ChanceDoubleDamage), "ModifyOutgoingHit", (Type[])null, (Type[])null));
			}

			private static void Prefix(HitData hit, out float __state)
			{
				__state = ((hit == null) ? 0f : hit.GetTotalDamage());
			}

			private static void Postfix(HitData hit, float __state)
			{
				if (hit == null || !(__state > 0f))
				{
					return;
				}
				float totalDamage = hit.GetTotalDamage();
				if (totalDamage != __state && totalDamage > 0f)
				{
					if (!Factors.TryGetValue(hit, out var value))
					{
						value = new StrongBox<float>(1f);
						Factors.Add(hit, value);
					}
					value.Value *= totalDamage / __state;
				}
			}
		}

		[HarmonyPatch]
		private static class BeforeStrikeMultipliers
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				return Required(AccessTools.Method(typeof(MeteorSummoner), "OnDamageDealt", (Type[])null, (Type[])null), AccessTools.Method(typeof(EikthyrShockingCharge), "OnDamageDealt", (Type[])null, (Type[])null));
			}

			private static void Prefix(HitData hit, out DamageTypes? __state)
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				__state = null;
				if (hit != null && StrikeMultipliers.Factors.TryGetValue(hit, out var value) && value.Value > 0f)
				{
					__state = hit.m_damage;
					((DamageTypes)(ref hit.m_damage)).Modify(1f / value.Value);
				}
			}

			private static void Finalizer(HitData hit, DamageTypes? __state)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				if (hit != null && __state.HasValue)
				{
					hit.m_damage = __state.Value;
				}
			}
		}

		private static IEnumerable<MethodBase> Required(params MethodBase[] methods)
		{
			if (methods.Any((MethodBase method) => method == null))
			{
				throw new InvalidOperationException("EpicLoot's crit, double damage, meteor or charge moved.");
			}
			return methods;
		}
	}
	internal static class BountyTargetStrength
	{
		private static readonly int BountyIdKey = StringExtensionMethods.GetStableHashCode("BountyID");

		private static readonly int BountyDataKey = StringExtensionMethods.GetStableHashCode("BountyData");

		private static readonly int IsAddKey = StringExtensionMethods.GetStableHashCode("IsAdd");

		private static readonly FieldRef<Character, ZNetView> NetViewOf = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");

		private static readonly Func<BountyInfo, bool, float> HealthModifier = AccessTools.MethodDelegate<Func<BountyInfo, bool, float>>(AccessTools.Method(typeof(BountyTarget), "GetMaxHealthModifier", (Type[])null, (Type[])null), (object)null, true);

		private static PropertyInfo baseValuesOf;

		private static object baseHealth;

		internal static void Initialize(Harmony harmony)
		{
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Expected O, but got Unknown
			//IL_01c4: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("MidnightsFX.StarLevelSystem", out var value))
			{
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				Type type = assembly.GetType("StarLevelSystem.Data.CompositeLazyCache");
				Type type2 = assembly.GetType("StarLevelSystem.common.DataObjects+CharacterCacheEntry");
				Type type3 = assembly.GetType("StarLevelSystem.common.DataObjects+CreatureBaseAttribute");
				Type type4 = assembly.GetType("StarLevelSystem.modules.Modifiers.CreatureModifiers");
				MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type, "ApplyPersistedStatOverrides", new Type[2]
				{
					typeof(ZDO),
					type2
				}, (Type[])null));
				baseValuesOf = AccessTools.Property(type2, "CreatureBaseValueModifiers");
				baseHealth = ((type3 != null && Enum.IsDefined(type3, "BaseHealth")) ? Enum.Parse(type3, "BaseHealth") : null);
				MethodInfo[] array = new MethodInfo[4]
				{
					AccessTools.Method(type, "GetAndSetLocalCache", (Type[])null, (Type[])null),
					AccessTools.Method(assembly.GetType("StarLevelSystem.modules.Damage.DamagePatches+ModifyDamagePerLevel"), "DetermineDamageFactor", (Type[])null, (Type[])null),
					AccessTools.Method(type4, "SelectModifiersForCreature", (Type[])null, (Type[])null),
					AccessTools.Method(type4, "TryRollEvolutionModifier", (Type[])null, (Type[])null)
				};
				if (methodInfo == null || baseValuesOf == null || baseHealth == null || array.Any((MethodInfo method) => method == null || method.GetParameters().FirstOrDefault()?.ParameterType != typeof(Character)))
				{
					throw new InvalidOperationException("StarLevelSystem's creature stats changed.");
				}
				Type typeFromHandle = typeof(BountyTargetStrength);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RestoreBonus", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				MethodInfo[] array2 = array;
				foreach (MethodInfo methodInfo2 in array2)
				{
					harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeFromHandle, "AsOrdinary", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "AsBoss", (Type[])null), (HarmonyMethod)null);
				}
			}
		}

		private static void RestoreBonus(ZDO __0, object __1)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			string text = ((__0 == null || __1 == null) ? "" : __0.GetString(BountyDataKey, ""));
			if (text.Length != 0)
			{
				BountyInfo arg;
				try
				{
					arg = BountyInfo.FromPackage(new ZPackage(text));
				}
				catch (Exception)
				{
					return;
				}
				((IDictionary)baseValuesOf.GetValue(__1))[baseHealth] = HealthModifier(arg, __0.GetBool(IsAddKey, false));
			}
		}

		private static void AsOrdinary(Character __0, out bool __state)
		{
			ZNetView val = (((Object)(object)__0 != (Object)null && __0.m_boss) ? NetViewOf.Invoke(__0) : null);
			ZDO val2 = (((Object)(object)val != (Object)null) ? val.GetZDO() : null);
			__state = val2 != null && val2.GetString(BountyIdKey, "").Length > 0;
			if (__state)
			{
				__0.m_boss = false;
			}
		}

		private static void AsBoss(Character __0, bool __state)
		{
			if (__state)
			{
				__0.m_boss = true;
			}
		}
	}
	[HarmonyPatch]
	internal static class BowAmmoDamage
	{
		private delegate void EnchantmentModifier(Player player, ItemData item, ref DamageTypes damage);

		private delegate void ShardModifier(ItemData item, ref DamageTypes damage);

		private static readonly EnchantmentModifier ApplyEnchantments = AccessTools.MethodDelegate<EnchantmentModifier>(AccessTools.Method(typeof(ModifyDamage), "ApplyMagicDamageModifiers", (Type[])null, (Type[])null), (object)null, true);

		private static readonly ShardModifier ApplyShards = AccessTools.MethodDelegate<ShardModifier>(AccessTools.Method(typeof(ModifyDamage), "ApplyShardWeaponModifiers", (Type[])null, (Type[])null), (object)null, true);

		private static readonly FieldRef<Attack, Humanoid> CharacterOf = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character");

		private static readonly FieldRef<Attack, ItemData> AmmoOf = AccessTools.FieldRefAccess<Attack, ItemData>("m_ammoItem");

		private static ItemData firingWeapon;

		private static ItemData firingAmmo;

		private static DamageTypes? ammoDamage;

		[HarmonyPatch(typeof(Attack), "FireProjectileBurst")]
		[HarmonyPrefix]
		private static void Fire(Attack __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			ItemData weapon = __instance.GetWeapon();
			ItemData val = AmmoOf.Invoke(__instance);
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)CharacterOf.Invoke(__instance) != (Object)(object)localPlayer) && weapon != null && val != null && val != weapon && !ItemDataExtensions.IsMagic(val))
			{
				firingWeapon = weapon;
				firingAmmo = val;
			}
		}

		[HarmonyPatch(typeof(Attack), "FireProjectileBurst")]
		[HarmonyFinalizer]
		private static void Fired()
		{
			firingWeapon = (firingAmmo = null);
			ammoDamage = null;
		}

		[HarmonyPatch(typeof(ItemData), "GetDamage", new Type[]
		{
			typeof(int),
			typeof(float)
		})]
		[HarmonyPostfix]
		[HarmonyPriority(800)]
		private static void KeepAmmoDamage(ItemData __instance, DamageTypes __result)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (__instance == firingAmmo && firingAmmo != null)
			{
				ammoDamage = __result;
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetDamage", new Type[]
		{
			typeof(int),
			typeof(float)
		})]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void UseWeaponModifiers(ItemData __instance, ref DamageTypes __result)
		{
			//IL_0022: 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)
			if (__instance == firingAmmo && firingAmmo != null && ammoDamage.HasValue)
			{
				__result = ammoDamage.Value;
				ammoDamage = null;
				ApplyEnchantments(Player.m_localPlayer, firingWeapon, ref __result);
				ApplyShards(firingWeapon, ref __result);
			}
		}
	}
	[HarmonyPatch(typeof(BulkupEffect), "GetHealthRegenWithBulkUp")]
	internal static class BulkUpRegen
	{
		private static bool Prefix(float regen, ref float __result)
		{
			float num = default(float);
			__result = (PlayerExtensions.HasActiveMagicEffect(Player.m_localPlayer, MagicEffectType.BulkUp, ref num, 0.01f, (ItemData)null) ? (regen * (1f - Mathf.Clamp01(num))) : regen);
			return false;
		}
	}
	[HarmonyPatch]
	internal static class ChainLightningJumps
	{
		private static readonly FieldRef<Aoe, Character> OwnerOf = AccessTools.FieldRefAccess<Aoe, Character>("m_owner");

		private static readonly FieldRef<Aoe, HitData> SettingsOf = AccessTools.FieldRefAccess<Aoe, HitData>("m_hitData");

		private static readonly FieldRef<Aoe, float> ChainChanceOf = AccessTools.FieldRefAccess<Aoe, float>("m_chainChance");

		private static readonly FieldRef<Aoe, int> StatusEffectOf = AccessTools.FieldRefAccess<Aoe, int>("m_statusEffectHash");

		private static readonly ConditionalWeakTable<HitData, object> Chains = new ConditionalWeakTable<HitData, object>();

		private static readonly object Chain = new object();

		[HarmonyPatch(typeof(ChainLightning), "TriggerChainLightningEffect")]
		[HarmonyPrefix]
		private static bool Strike(Character target, Player player)
		{
			//IL_0020: 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_0097: 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_009e: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			GameObject prefab = ZNetScene.instance.GetPrefab("ChainLightning");
			Aoe val = (((Object)(object)prefab == (Object)null) ? null : Object.Instantiate<GameObject>(prefab, ((Component)target).transform.position, Quaternion.identity).GetComponent<Aoe>());
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			HitSource.MarkBonusSource(((Component)val).gameObject);
			OwnerOf.Invoke(val) = (Character)(object)player;
			ChainChanceOf.Invoke(val) = 0.8f;
			val.m_chainStartChanceFalloff = 0.8f;
			val.m_damage.m_lightning *= PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.ChainLightning, 0.01f, (ItemData)null);
			HitData val2 = new HitData
			{
				m_damage = val.m_damage,
				m_blockable = val.m_blockable,
				m_dodgeable = val.m_dodgeable,
				m_pushForce = val.m_attackForce,
				m_backstabBonus = val.m_backstabBonus,
				m_statusEffectHash = StatusEffectOf.Invoke(val),
				m_toolTier = (short)val.m_toolTier,
				m_skill = (SkillType)999
			};
			SettingsOf.Invoke(val) = val2;
			Chains.Add(val2, Chain);
			return false;
		}

		[HarmonyPatch(typeof(Aoe), "CustomFixedUpdate")]
		[HarmonyPrefix]
		private static void RollChainChance(Aoe __instance)
		{
			if (__instance.m_chainStartChance > 0f && (Object)(object)__instance.m_chainObj != (Object)null && IsChain(__instance))
			{
				__instance.m_chainStartChance = ChainChanceOf.Invoke(__instance);
			}
		}

		internal static bool IsChain(Aoe aoe)
		{
			HitData val = SettingsOf.Invoke(aoe);
			object value;
			if (val != null)
			{
				return Chains.TryGetValue(val, out value);
			}
			return false;
		}
	}
	internal static class ChestSupplySwitch
	{
		private delegate bool ContainerSwitch(Container container, Humanoid character, bool hold, bool alt, ref bool handled);

		private const KeyCode Key = (KeyCode)108;

		private const string UseKeyText = " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood ";

		private static ContainerSwitch switchContainer;

		private static Func<Player, bool> takeInput;

		private static bool switching;

		internal static void Initialize(Harmony harmony, ManualLogSource log)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.TryGetValue("Azumatt.AzuCraftyBoxes", out var value))
			{
				return;
			}
			Assembly assembly = ((object)value.Instance).GetType().Assembly;
			MethodInfo methodInfo = AccessTools.Method(assembly.GetType("AzuCraftyBoxes.Patches.ChestBlockInteraction"), "Prefix", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(assembly.GetType("AzuCraftyBoxes.Patches.CraftyToggle"), "HoverLine", new Type[1] { typeof(bool) }, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(Player), "TakeInput", Type.EmptyTypes, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || methodInfo3 == null)
			{
				throw new InvalidOperationException("AzuCraftyBoxes' chest switch moved.");
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ChestSupplySwitch), "OnlyOnSwitchKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ChestSupplySwitch), "ShowSwitchKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ChestSupplySwitch), "SwitchOnKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			switchContainer = AccessTools.MethodDelegate<ContainerSwitch>(methodInfo, (object)null, true);
			takeInput = AccessTools.MethodDelegate<Func<Player, bool>>(methodInfo3, (object)null, true);
			if (Chainloader.PluginInfos.TryGetValue("goldenrevolver.quick_stack_store", out var value2))
			{
				MethodInfo methodInfo4 = AccessTools.Method(((object)value2.Instance).GetType().Assembly.GetType("QuickStackStore.KeybindChecker"), "IsKeyDown", new Type[1] { typeof(KeyboardShortcut) }, (Type[])null);
				if (methodInfo4 == null)
				{
					throw new InvalidOperationException("Quick Stack's hotkey check moved.");
				}
				harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(ChestSupplySwitch), "NotOnSwitchKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			log.LogInfo((object)"AzuCraftyBoxes' chest supply switch is on Shift + L instead of Shift + E.");
		}

		private static bool OnKeyboard()
		{
			return !ZInput.IsGamepadActive();
		}

		private static void OnlyOnSwitchKey(ref bool __3)
		{
			if (!switching && OnKeyboard())
			{
				__3 = false;
			}
		}

		private static void SwitchOnKey(Player __instance)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Input.GetKeyDown((KeyCode)108) || !ZInput.GetButton("AltPlace") || !OnKeyboard() || !takeInput(__instance))
			{
				return;
			}
			GameObject hoverObject = ((Humanoid)__instance).GetHoverObject();
			Container val = (((Object)(object)hoverObject == (Object)null) ? null : hoverObject.GetComponentInParent<Container>());
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			bool handled = false;
			switching = true;
			try
			{
				switchContainer(val, (Humanoid)(object)__instance, hold: false, alt: true, ref handled);
			}
			finally
			{
				switching = false;
			}
		}

		private static IEnumerable<CodeInstruction> ShowSwitchKey(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			List<CodeInstruction> list2 = list.Where((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldstr && (string)instruction.operand == " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood ").ToList();
			if (list2.Count != 1)
			{
				throw new InvalidOperationException("AzuCraftyBoxes' chest switch hover text changed.");
			}
			list2[0].opcode = OpCodes.Call;
			list2[0].operand = AccessTools.Method(typeof(ChestSupplySwitch), "SwitchKeyText", (Type[])null, (Type[])null);
			return list;
		}

		private static string SwitchKeyText()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!OnKeyboard())
			{
				return " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood ";
			}
			return " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood ".Replace("$KEY_Use", ((object)(KeyCode)108/*cast due to .constrained prefix*/).ToString());
		}

		private static bool NotOnSwitchKey(KeyboardShortcut __0, ref bool __result)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			if ((int)((KeyboardShortcut)(ref __0)).MainKey != 108 || ((KeyboardShortcut)(ref __0)).Modifiers.Any() || !ZInput.GetButton("AltPlace"))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(CoinHoarder), "GetCoinHoarderValue")]
	internal static class CoinHoarderBonus
	{
		private static readonly Func<Player, int> TotalCoins = AccessTools.MethodDelegate<Func<Player, int>>(AccessTools.Method(typeof(CoinHoarder).Assembly.GetType("EpicLoot.General.CoinPurse"), "GetTotalCoins", new Type[1] { typeof(Player) }, (Type[])null), (object)null, true);

		private static bool Prefix(Player player, float effectValue, ref float __result)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			float num = TotalCoins(player);
			if (num > 1000f)
			{
				return true;
			}
			__result = ((num <= 0f || effectValue <= 0f) ? 0f : (num / 1000f * (Mathf.Log10(effectValue * 1000f) * 6.258f / 150f)));
			return false;
		}
	}
	internal static class ComfortRoomPanel
	{
		private static FieldRef<Player, PieceTable> placeModePieces;

		internal static void Initialize(Harmony harmony, ManualLogSource log)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("hardwire99.comfortme", out var value))
			{
				Type type = ((object)value.Instance).GetType().Assembly.GetType("ComfortMe.HudUi");
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "HoldingPlaceTool", Type.EmptyTypes, (Type[])null));
				if (methodInfo == null || !methodInfo.IsStatic || methodInfo.ReturnType != typeof(bool))
				{
					throw new InvalidOperationException("ComfortMe's build tool check moved.");
				}
				placeModePieces = AccessTools.FieldRefAccess<Player, PieceTable>("m_buildPieces");
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ComfortRoomPanel), "OnlyWithHammer", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				log.LogInfo((object)"ComfortMe's This room panel shows only with the hammer.");
			}
		}

		private static void OnlyWithHammer(ref bool __result)
		{
			if (__result)
			{
				Player localPlayer = Player.m_localPlayer;
				PieceTable val = (((Object)(object)localPlayer != (Object)null) ? placeModePieces.Invoke(localPlayer) : null);
				__result = (Object)(object)val != (Object)null && ((Object)val).name == PieceTables.Hammer;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	internal static class CraftingBonus
	{
		private static readonly FieldRef<InventoryGui, Recipe> CraftRecipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe");

		private static readonly FieldRef<InventoryGui, ItemData> CraftUpgradeItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem");

		internal static void Initialize(Harmony harmony, ManualLogSource logger)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("Azumatt.AzuAntiArthriticCrafting", out var value))
			{
				MethodInfo methodInfo = AccessTools.Method(((object)value.Instance)?.GetType().Assembly.GetType("AzuAntiArthriticCrafting.Patches.SequentialSkillBonus"), "Postfix", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					throw new InvalidOperationException("AAA_Crafting's sequential skill bonus changed.");
				}
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CraftingBonus), "SkipStreak", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				logger.LogInfo((object)"AAA_Crafting's sequential bonus streak is disabled; each crafting bonus adds one full craft.");
			}
		}

		private static bool SkipStreak()
		{
			return false;
		}

		private static int BonusPerRoll(int bonusAmount, InventoryGui gui, int amount)
		{
			Recipe val = CraftRecipe.Invoke(gui);
			ItemData val2 = CraftUpgradeItem.Invoke(gui);
			int num2 = default(int);
			ItemData val3 = default(ItemData);
			int num = bonusAmount * val.GetAmount((val2 == null) ? 1 : (val2.m_quality + 1), ref num2, ref val3, 1);
			if (val2 == null && !((Humanoid)Player.m_localPlayer).GetInventory().CanAddItem(((Component)val.m_item).gameObject, amount + num))
			{
				return 0;
			}
			return num;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected O, but got Unknown
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.ToList();
			FieldInfo bonusAmount = AccessTools.Field(typeof(InventoryGui), "m_craftBonusAmount");
			int num = list.FindIndex((CodeInstruction x) => CodeInstructionExtensions.LoadsField(x, bonusAmount, false));
			if (num < 0 || list.FindLastIndex((CodeInstruction x) => CodeInstructionExtensions.LoadsField(x, bonusAmount, false)) != num || num + 6 >= list.Count || list[num + 1].opcode != OpCodes.Add || !CodeInstructionExtensions.IsStloc(list[num + 2], (LocalBuilder)null) || !CodeInstructionExtensions.IsLdloc(list[num + 3], (LocalBuilder)null) || !CodeInstructionExtensions.IsLdloc(list[num + 4], (LocalBuilder)null) || !SameLocal(list[num + 4], list[num + 2]) || list[num + 5].opcode != OpCodes.Add || !CodeInstructionExtensions.IsStloc(list[num + 6], (LocalBuilder)null) || !SameLocal(list[num + 6], list[num + 3]))
			{
				throw new InvalidOperationException("Valheim's crafting bonus changed; expected one bonus accumulation.");
			}
			LocalBuilder localBuilder = generator.DeclareLocal(typeof(int));
			list[num + 4].opcode = OpCodes.Ldloc;
			list[num + 4].operand = localBuilder;
			list.InsertRange(num + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[5]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(list[num + 3].opcode, list[num + 3].operand),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(CraftingBonus), "BonusPerRoll", (Type[])null, (Type[])null)),
				new CodeInstruction(OpCodes.Dup, (object)null),
				new CodeInstruction(OpCodes.Stloc, (object)localBuilder)
			});
			return list;
		}

		private static bool SameLocal(CodeInstruction first, CodeInstruction second)
		{
			if (first.operand is LocalVariableInfo localVariableInfo && second.operand is LocalVariableInfo localVariableInfo2)
			{
				return localVariableInfo.LocalIndex == localVariableInfo2.LocalIndex;
			}
			return false;
		}
	}
	internal static class CraftingHistory
	{
		private sealed class MigrationRecord
		{
			[JsonProperty(/*Could not decode attribute arguments.*/)]
			public int Version = 1;

			[JsonProperty(/*Could not decode attribute arguments.*/)]
			public string[] Items = Array.Empty<string>();
		}

		private const string StateKey = "valheim.epiclootprogressionfix.crafting-migration";

		private static readonly FieldRef<Player, HashSet<string>> KnownMaterials = AccessTools.FieldRefAccess<Player, HashSet<string>>("m_knownMaterial");

		private static readonly FieldRef<PlayerProfile, byte[]> SavedPlayerData = AccessTools.FieldRefAccess<PlayerProfile, byte[]>("m_playerData");

		private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
		{
			TypeNameHandling = (TypeNameHandling)0
		};

		private static FieldInfo acquireCharacterFromTemplate;

		private static ManualLogSource logger;

		private static Player owner;

		private static PlayerProfile profile;

		private static HashSet<string> legacyCredits;

		private static bool spawning;

		private static bool freshCharacter;

		private static ZNetScene conversionScene;

		private static Dictionary<string, HashSet<string>> conversionSources;

		internal static string Problem { get; private set; }

		internal static void Initialize(Harmony harmony, ManualLogSource log)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			logger = log;
			if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.servercharacters", out var value))
			{
				if (value.Metadata.Version != new Version(1, 4, 17))
				{
					throw new InvalidOperationException("Crafting migration requires ServerCharacters 1.4.17 when installed.");
				}
				acquireCharacterFromTemplate = AccessTools.Field(((object)value.Instance).GetType().Assembly.GetType("ServerCharacters.ClientSide", throwOnError: true), "acquireCharacterFromTemplate");
				if (acquireCharacterFromTemplate == null || !acquireCharacterFromTemplate.IsStatic || acquireCharacterFromTemplate.FieldType != typeof(bool))
				{
					throw new MissingFieldException("ServerCharacters character initialization changed.");
				}
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(Game), "SpawnPlayer", (Type[])null, (Type[])null);
			HarmonyMethod obj = Patch("BeforeSpawn");
			HarmonyMethod val = new HarmonyMethod(typeof(CraftingHistory), "AfterSpawn", (Type[])null);
			val.priority = 0;
			val.after = new string[1] { "org.bepinex.plugins.servercharacters" };
			harmony.Patch((MethodBase)methodInfo, obj, val, (HarmonyMethod)null, Patch("SpawnFailed"), (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "Load", (Type[])null, (Type[])null), Patch("BeforeLoad"), Patch("AfterLoad"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "Save", (Type[])null, (Type[])null), Patch("BeforeSave"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static HarmonyMethod Patch(string name)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return new HarmonyMethod(typeof(CraftingHistory), name, (Type[])null);
		}

		private static void Reset()
		{
			owner = null;
			profile = null;
			legacyCredits = null;
			Problem = null;
		}

		private static void BeforeSpawn()
		{
			Reset();
			spawning = true;
			freshCharacter = SavedPlayerData.Invoke(Game.instance.GetPlayerProfile()) == null || (acquireCharacterFromTemplate != null && (bool)acquireCharacterFromTemplate.GetValue(null));
		}

		private static void AfterSpawn()
		{
			spawning = false;
			Attach(freshCharacter);
		}

		private static void SpawnFailed(Exception __exception)
		{
			if (__exception != null)
			{
				spawning = false;
				Reset();
			}
		}

		private static void BeforeLoad(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Reset();
			}
		}

		private static void AfterLoad(Player __instance)
		{
			if (!spawning && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Attach(fresh: false);
			}
		}

		private static void BeforeSave(Player __instance)
		{
			if (spawning && freshCharacter && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && !__instance.m_customData.ContainsKey("valheim.epiclootprogressionfix.crafting-migration"))
			{
				__instance.m_customData["valheim.epiclootprogressionfix.crafting-migration"] = JsonConvert.SerializeObject((object)new MigrationRecord(), JsonSettings);
			}
		}

		private static bool CreationRecipe(Recipe recipe)
		{
			if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item != (Object)null && recipe.m_amount > 0)
			{
				if (!((Object)(object)recipe.m_craftingStation == (Object)null))
				{
					return !recipe.m_craftingStation.m_upgrader;
				}
				return true;
			}
			return false;
		}

		private static void Attach(bool fresh)
		{
			Reset();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			try
			{
				PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
				if (playerProfile.GetPlayerID() != localPlayer.GetPlayerID())
				{
					throw new InvalidOperationException("The loaded character does not match its crafting profile.");
				}
				HashSet<string> hashSet;
				if (localPlayer.m_customData.TryGetValue("valheim.epiclootprogressionfix.crafting-migration", out var value))
				{
					MigrationRecord migrationRecord = JsonConvert.DeserializeObject<MigrationRecord>(value, JsonSettings);
					if (migrationRecord == null || migrationRecord.Version != 1 || migrationRecord.Items == null || migrationRecord.Items.Any(string.IsNullOrEmpty))
					{
						throw new InvalidDataException("Invalid saved crafting migration; original data has been left intact.");
					}
					hashSet = new HashSet<string>(migrationRecord.Items, StringComparer.Ordinal);
				}
				else
				{
					hashSet = new HashSet<string>(StringComparer.Ordinal);
					if (!fresh)
					{
						ObjectDB instance = ObjectDB.instance;
						if ((Object)(object)instance == (Object)null || !instance.m_recipes.Any(CreationRecipe))
						{
							throw new InvalidOperationException("Crafting recipes are unavailable; migration was not saved.");
						}
						foreach (Recipe item in instance.m_recipes.Where(CreationRecipe))
						{
							ItemData itemData = item.m_item.m_itemData;
							if (EpicLoot.IsAllowedMagicItemType(itemData) && KnownMaterials.Invoke(localPlayer).Contains(itemData.m_shared.m_name) && !LootDenyList.IsDenied(((Object)((Component)item.m_item).gameObject).name))
							{
								hashSet.Add(itemData.m_shared.m_name);
							}
						}
					}
					localPlayer.m_customData["valheim.epiclootprogressionfix.crafting-migration"] = JsonConvert.SerializeObject((object)new MigrationRecord
					{
						Items = hashSet.OrderBy<string, string>((string name) => name, StringComparer.Ordinal).ToArray()
					}, JsonSettings);
					logger.LogInfo((object)$"Crafting migration saved {hashSet.Count} legacy credits for this character.");
				}
				owner = localPlayer;
				profile = playerProfile;
				legacyCredits = hashSet;
			}
			catch (Exception ex)
			{
				Problem = "Crafting history could not load: " + ex.GetBaseException().Message;
				logger.LogError((object)Problem);
			}
		}

		internal static bool IsUnlocked(string prefabName)
		{
			Player localPlayer = Player.m_localPlayer;
			if (string.IsNullOrEmpty(prefabName) || (Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer != (Object)(object)owner || profile == null || legacyCredits == null || Game.instance.GetPlayerProfile() != profile || localPlayer.GetPlayerID() != profile.GetPlayerID())
			{
				return false;
			}
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			string name = val2.m_itemData.m_shared.m_name;
			Dictionary<string, float> crafts = profile.m_playerStats[0].m_itemCraftStats;
			if (legacyCredits.Contains(name))
			{
				return true;
			}
			if (ConversionSources().TryGetValue(name, out var value))
			{
				if (!value.Any(Crafted))
				{
					if (Crafted(name))
					{
						return HasCreationRecipe();
					}
					return false;
				}
				return true;
			}
			if (Crafted(name))
			{
				return true;
			}
			if (prefabName == "FishingRod" && KnownMaterials.Invoke(localPlayer).Contains(name))
			{
				return !HasCreationRecipe();
			}
			return false;
			bool Crafted(string item)
			{
				if (crafts.TryGetValue(item, out var value2))
				{
					return value2 > 0f;
				}
				return false;
			}
			bool HasCreationRecipe()
			{
				return ObjectDB.instance.m_recipes.Any((Recipe recipe) => CreationRecipe(recipe) && recipe.m_item.m_itemData.m_shared.m_name == name);
			}
		}

		private static Dictionary<string, HashSet<string>> ConversionSources()
		{
			ZNetScene instance = ZNetScene.instance;
			if (conversionSources != null && (Object)(object)conversionScene == (Object)(object)instance)
			{
				return conversionSources;
			}
			Dictionary<string, HashSet<string>> dictionary = new Dictionary<string, HashSet<string>>(StringComparer.Ordinal);
			if ((Object)(object)instance != (Object)null)
			{
				foreach (GameObject prefab in instance.m_prefabs)
				{
					if ((Object)(object)prefab == (Object)null)
					{
						continue;
					}
					CookingStation[] componentsInChildren = prefab.GetComponentsInChildren<CookingStation>(true);
					for (int i = 0; i < componentsInChildren.Length; i++)
					{
						foreach (ItemConversion item in componentsInChildren[i].m_conversion ?? new List<ItemConversion>())
						{
							if (!((Object)(object)item?.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null))
							{
								string name = item.m_to.m_itemData.m_shared.m_name;
								if (!dictionary.TryGetValue(name, out var value))
								{
									value = (dictionary[name] = new HashSet<string>(StringComparer.Ordinal));
								}
								value.Add(item.m_from.m_itemData.m_shared.m_name);
							}
						}
					}
				}
			}
			conversionScene = instance;
			conversionSources = dictionary;
			return dictionary;
		}
	}
	[HarmonyPatch(typeof(GatedItemTypeHelper), "CheckIfItemNeedsGate", new Type[]
	{
		typeof(GatedItemTypeMode),
		typeof(string)
	})]
	internal static class CraftedEquipmentGate
	{
		private static bool Prefix(GatedItemTypeMode mode, string itemName, ref bool __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)mode != 4 || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			__result = !CraftingHistory.IsUnlocked(itemName);
			return false;
		}
	}
	internal static class CreatureAreaDamage
	{
		private static readonly int FactorKey = StringExtensionMethods.GetStableHashCode("epicloot_progression_creature_damage_factor");

		private static readonly FieldRef<Aoe, ZNetView> NetViewOf = AccessTools.FieldRefAccess<Aoe, ZNetView>("m_nview");

		private static readonly FieldRef<Attack, Humanoid> AttackerOf = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character");

		private static readonly FieldRef<SpawnAbility, Character> SpawnerOf = AccessTools.FieldRefAccess<SpawnAbility, Character>("m_owner");

		private static readonly ConditionalWeakTable<Aoe, StrongBox<float>> Factors = new ConditionalWeakTable<Aoe, StrongBox<float>>();

		private static Func<Character, float> factorOf;

		private static float creating = 1f;

		internal static void Initialize(Harmony harmony)
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_01b1: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			//IL_01e1: Expected O, but got Unknown
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Expected O, but got Unknown
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("MidnightsFX.StarLevelSystem", out var value))
			{
				MethodInfo methodInfo = AccessTools.Method(((object)value.Instance).GetType().Assembly.GetType("StarLevelSystem.modules.Damage.DamagePatches+ModifyDamagePerLevel"), "DetermineDamageFactor", new Type[1] { typeof(Character) }, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Aoe), "OnHit", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(typeof(Attack), "DoAreaAttack", (Type[])null, (Type[])null);
				MethodInfo methodInfo4 = AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(SpawnAbility), "Spawn", (Type[])null, (Type[])null));
				if (methodInfo == null || methodInfo.ReturnType != typeof(float) || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null)
				{
					throw new InvalidOperationException("StarLevelSystem's damage factor or the game's area effects changed.");
				}
				factorOf = AccessTools.MethodDelegate<Func<Character, float>>(methodInfo, (object)null, true);
				Type typeFromHandle = typeof(CreatureAreaDamage);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(Aoe), "Setup", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RememberArea", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "ScaleHits", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(Projectile), "Setup", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "ScaleProjectile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(Character), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(typeFromHandle, "BeginDeath", (Type[])null)
				{
					priority = 800
				}, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "EndCreating", (Type[])null), (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeFromHandle, "BeginAreaAttack", (Type[])null)
				{
					priority = 800
				}, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "EndCreating", (Type[])null), (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(EffectList), "Create", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RememberCreated", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RememberSpawned", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static float FactorFor(Character owner, HitData hitData, bool usesHit)
		{
			if (!((Object)(object)owner == (Object)null) && !owner.IsPlayer() && !(hitData != null && usesHit))
			{
				return factorOf(owner);
			}
			return 1f;
		}

		private static Character PartOf(Aoe area)
		{
			ZNetView val = NetViewOf.Invoke(area);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return ((Component)val).GetComponent<Character>();
		}

		private static void Remember(Aoe area, float factor)
		{
			Factors.Remove(area);
			Factors.Add(area, new StrongBox<float>(factor));
			ZNetView val = NetViewOf.Invoke(area);
			if (factor != 1f && Object.op_Implicit((Object)(object)val) && val.IsValid() && val.IsOwner())
			{
				val.GetZDO().Set(FactorKey, factor);
			}
		}

		private static void RememberArea(Aoe __instance, Character owner, HitData hitData)
		{
			if (!Object.op_Implicit((Object)(object)PartOf(__instance)))
			{
				Remember(__instance, FactorFor(owner, hitData, __instance.m_useAttackSettings));
			}
		}

		private static IEnumerable<CodeInstruction> ScaleHits(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			MethodInfo damage = AccessTools.Method(typeof(Aoe), "GetDamage", Type.EmptyTypes, (Type[])null);
			List<CodeInstruction> code = instructions.ToList();
			List<int> list = (from i in Enumerable.Range(0, code.Count)
				where CodeInstructionExtensions.Calls(code[i], damage)
				select i).ToList();
			if (damage == null || list.Count != 1)
			{
				throw new InvalidOperationException("The game's area hits changed.");
			}
			code.InsertRange(list[0] + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(CreatureAreaDamage), "Scale", (Type[])null, (Type[])null))
			});
			return code;
		}

		private static DamageTypes Scale(DamageTypes damage, Aoe area)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			Character val = PartOf(area);
			float num = ((!Object.op_Implicit((Object)(object)val)) ? Factors.GetValue(area, Synced).Value : (val.IsPlayer() ? 1f : factorOf(val)));
			if (num != 1f)
			{
				((DamageTypes)(ref damage)).Modify(num);
			}
			return damage;
		}

		private static StrongBox<float> Synced(Aoe area)
		{
			ZNetView val = NetViewOf.Invoke(area);
			return new StrongBox<float>((Object.op_Implicit((Object)(object)val) && val.IsValid()) ? val.GetZDO().GetFloat(FactorKey, 1f) : 1f);
		}

		private static void ScaleProjectile(Projectile __instance, Character owner, HitData hitData)
		{
			float num = FactorFor(owner, hitData, usesHit: true);
			if (num != 1f)
			{
				((DamageTypes)(ref __instance.m_damage)).Modify(num);
			}
		}

		private static void BeginDeath(Character __instance, out float? __state)
		{
			__state = creating;
			creating = ((__instance.IsPlayer() || !__instance.IsOwner()) ? 1f : factorOf(__instance));
		}

		private static void BeginAreaAttack(Attack __instance, out float? __state)
		{
			__state = creating;
			Humanoid val = AttackerOf.Invoke(__instance);
			creating = ((!Object.op_Implicit((Object)(object)val) || ((Character)val).IsPlayer()) ? 1f : factorOf((Character)(object)val));
		}

		private static void EndCreating(float? __state)
		{
			if (__state.HasValue)
			{
				creating = __state.Value;
			}
		}

		private static void RememberCreated(GameObject[] __result)
		{
			if (creating == 1f || __result == null)
			{
				return;
			}
			foreach (GameObject val in __result)
			{
				Aoe val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Aoe>() : null);
				if (Object.op_Implicit((Object)(object)val2))
				{
					Remember(val2, creating);
				}
			}
		}

		private static IEnumerable<CodeInstruction> RememberSpawned(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			FieldInfo fieldInfo = AccessTools.Field(__originalMethod.DeclaringType, "<>4__this");
			List<CodeInstruction> code = instructions.ToList();
			List<int> list = (from i in Enumerable.Range(0, code.Count)
				where code[i].operand is MethodInfo { Name: "Instantiate" } methodInfo && methodInfo.ReturnType == typeof(GameObject)
				select i).ToList();
			if (fieldInfo == null || list.Count != 1)
			{
				throw new InvalidOperationException("The game's spawn ability changed.");
			}
			code.InsertRange(list[0] + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4]
			{
				new CodeInstruction(OpCodes.Dup, (object)null),
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo),
				new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(CreatureAreaDamage), "Spawned", (Type[])null, (Type[])null))
			});
			return code;
		}

		private static void Spawned(GameObject spawned, SpawnAbility ability)
		{
			Character val = SpawnerOf.Invoke(ability);
			Aoe val2 = (Object.op_Implicit((Object)(object)spawned) ? spawned.GetComponent<Aoe>() : null);
			if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val) && !val.IsPlayer())
			{
				Remember(val2, factorOf(val));
			}
		}
	}
	internal static class DamageTakenEffects
	{
		internal static void Initialize(Harmony harmony)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			Assembly assembly = typeof(ModifyDamage).Assembly;
			MethodInfo methodInfo = AccessTools.Method(assembly.GetType("EpicLoot.src.Magic.MagicItemEffects.Helpers.SharedCharacterRpcDamagePatch"), "Prefix", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(assembly.GetType("EpicLoot.src.Magic.MagicItemEffects.Helpers.SharedPlayerPostArmorDamagePatch"), "Postfix", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				throw new InvalidOperationException("EpicLoot's damage-taken effects moved.");
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DamageTakenEffects), "SkipFall", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(DamageTakenEffects), "NotForFalls", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static bool SkipFall(HitData hit, ref bool __result)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if (hit == null || (int)hit.m_hitType != 3)
			{
				return true;
			}
			__result = true;
			return false;
		}

		private static bool NotForFalls(HitData hit)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			if (hit != null)
			{
				return (int)hit.m_hitType != 3;
			}
			return true;
		}
	}
	internal static class DeathFeedWithoutEmbed
	{
		private static MethodInfo sendMessage;

		private static object deathFeed;

		internal static void Initialize(Harmony harmony)
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			if (Chainloader.PluginInfos.TryGetValue("RustyMods.DiscordBot", out var value))
			{
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				Type type = assembly.GetType("DiscordBot.Discord");
				Type type2 = assembly.GetType("DiscordBot.Webhook");
				Type type3 = assembly.GetType("DiscordBot.WebhookRoute");
				if (type == null || type2 == null || type3 == null || !type2.IsEnum || !Enum.IsDefined(type2, "DeathFeed"))
				{
					throw new InvalidOperationException("DiscordBot webhook API changed.");
				}
				MethodInfo methodInfo = AccessTools.Method(type, "SendEmbedMessage", new Type[6]
				{
					type2,
					typeof(string),
					typeof(string),
					typeof(string),
					typeof(string),
					type3
				}, (Type[])null);
				sendMessage = AccessTools.Method(type, "SendMessage", new Type[5]
				{
					type2,
					typeof(string),
					typeof(string),
					typeof(List<string>),
					type3
				}, (Type[])null);
				if (methodInfo == null || sendMessage == null)
				{
					throw new InvalidOperationException("DiscordBot webhook API changed.");
				}
				deathFeed = Enum.Parse(type2, "DeathFeed");
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DeathFeedWithoutEmbed), "SendEmbedMessage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static bool SendEmbedMessage(object __instance, object[] __args)
		{
			if (!object.Equals(__args[0], deathFeed))
			{
				return true;
			}
			string text = (string)__args[2];
			if (string.IsNullOrWhiteSpace(text))
			{
				return true;
			}
			sendMessage.Invoke(__instance, new object[5]
			{
				__args[0],
				__args[3],
				DeathMessageFormatting.ForDiscord(text),
				null,
				__args[5]
			});
			return false;
		}
	}
	internal static class DeathLeaderboard
	{
		private sealed class DeliveryState
		{
			public DateTime RecordingSinceUtc;

			public DateTime CompletedUtc;

			public DateTime PendingUtc;

			public string PendingContent;

			public DateTime RetryAfterUtc;
		}

		private sealed class Ranking
		{
			public string PlayerId;

			public string Name;

			public int Count;

			public DateTime LatestUtc;
		}

		private static ManualLogSource logger;

		private static FieldInfo database;

		private static FieldInfo configuration;

		private static FieldInfo deaths;

		private static PropertyInfo recordDate;

		private static PropertyInfo recordName;

		private static PropertyInfo recordPlayer;

		private static MethodInfo findAll;

		private static MethodInfo recordDeath;

		private static MethodInfo insertDeathRecord;

		private static ConstructorInfo createDeathRecord;

		private static HashSet<string> joinedPlayers;

		private static readonly Dictionary<ZRpc, ZDOID> recordedCharacters = new Dictionary<ZRpc, ZDOID>();

		private static readonly int deathMessage = StringExtensionMethods.GetStableHashCode("OnDeath");

		private static TimeZoneInfo warsaw;

		private static volatile bool running;

		private static DateTime nextCheckUtc;

		private static bool announced;

		internal static void Initialize(Harmony harmony, ManualLogSource log)
		{
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Expected O, but got Unknown
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Expected O, but got Unknown
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Expected O, but got Unknown
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Expected O, but got Unknown
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Expected O, but got Unknown
			if (Plugin.DailyDeathLeaderboard.Value && Chainloader.PluginInfos.TryGetValue("nwesterhausen.DiscordConnector", out var value))
			{
				if (value.Metadata.Version != new Version(3, 1, 3))
				{
					throw new InvalidOperationException("Death leaderboard requires DiscordConnector 3.1.3.");
				}
				logger = log;
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				database = AccessTools.Field(((object)value.Instance).GetType(), "StaticDatabase");
				configuration = AccessTools.Field(((object)value.Instance).GetType(), "StaticConfig");
				deaths = AccessTools.Field(assembly.GetType("DiscordConnector.Records.Database"), "DeathCollection");
				Type type = assembly.GetType("DiscordConnector.Records.SimpleStat", throwOnError: true);
				recordDate = AccessTools.Property(type, "Date");
				recordName = AccessTools.Property(type, "Name");
				recordPlayer = AccessTools.Property(type, "PlayerId");
				findAll = ((deaths == null) ? null : AccessTools.Method(deaths.FieldType, "FindAll", (Type[])null, (Type[])null));
				insertDeathRecord = ((deaths == null) ? null : AccessTools.Method(deaths.FieldType, "Insert", new Type[1] { type }, (Type[])null));
				createDeathRecord = AccessTools.Constructor(type, new Type[5]
				{
					typeof(string),
					typeof(string),
					typeof(float),
					typeof(float),
					typeof(float)
				}, false);
				Type type2 = assembly.GetType("DiscordConnector.Handlers", throwOnError: true);
				recordDeath = AccessTools.Method(type2, "Death", (Type[])null, (Type[])null);
				joinedPlayers = (HashSet<string>)(AccessTools.Field(type2, "joinedPlayers")?.GetValue(null));
				if (database == null || configuration == null || findAll == null || recordDate == null || recordName == null || recordPlayer == null || recordDeath == null || joinedPlayers == null || insertDeathRecord == null || createDeathRecord == null)
				{
					throw new InvalidOperationException("DiscordConnector death-record API changed.");
				}
				try
				{
					warsaw = TimeZoneInfo.FindSystemTimeZoneById("Europe/Warsaw");
				}
				catch (TimeZoneNotFoundException)
				{
					warsaw = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
				}
				harmony.Patch((MethodBase)AccessTools.Method(type2, "Join", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DeathLeaderboard), "FirstSpawnOnly", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(ZRoutedRpc), "RPC_RoutedRPC", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathLeaderboard), "ObserveDeathMessage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(deaths.DeclaringType, "InsertSimpleStatRecord", new Type[4]
				{
					deaths.FieldType,
					typeof(string),
					typeof(string),
					typeof(Vector3)
				}, (Type[])null), new HarmonyMethod(typeof(DeathLeaderboard), "StoreDeath", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "Disconnect", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(DeathLeaderboard), "ForgetPeer", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DeathLeaderboard), "ClearDeaths", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				logger.LogInfo((object)"Daily death leaderboard initialized: 06:00 Europe/Warsaw, preceding 24 hours.");
			}
		}

		private static bool FirstSpawnOnly(ZNetPeer peer)
		{
			if (peer != null)
			{
				return !joinedPlayers.Contains(peer.m_socket.GetHostName());
			}
			return true;
		}

		private static IEnumerable<CodeInstruction> ObserveDeathMessage(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			LocalVariableInfo data = __originalMethod.GetMethodBody().LocalVariables.Single((LocalVariableInfo local) => local.LocalType == typeof(RoutedRPCData));
			MethodInfo deserialize = AccessTools.Method(typeof(RoutedRPCData), "Deserialize", (Type[])null, (Type[])null);
			int changes = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				yield return instruction;
				if (CodeInstructionExtensions.Calls(instruction, deserialize))
				{
					yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null);
					yield return new CodeInstruction(OpCodes.Ldloc, (object)data.LocalIndex);
					yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DeathLeaderboard), "ReceiveDeath", (Type[])null, (Type[])null));
					changes++;
				}
			}
			if (changes != 1)
			{
				throw new InvalidOperationException("Native death-message routing changed.");
			}
		}

		private static void ReceiveDeath(ZRpc rpc, RoutedRPCData data)
		{
			//IL_0065: 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_0077: 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_009d: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (!ZNet.instance.IsServer() || data.m_methodHash != deathMessage || data.m_targetPeerID != 0L)
			{
				return;
			}
			ZNetPeer val = ZNet.instance.GetPeers().Find((ZNetPeer candidate) => candidate.m_rpc == rpc);
			if (val == null || !val.IsReady() || data.m_senderPeerID != val.m_uid || val.m_characterID == ZDOID.None || data.m_targetZDO != val.m_characterID || (recordedCharacters.TryGetValue(rpc, out var value) && value == data.m_targetZDO) || !joinedPlayers.Contains(val.m_socket.GetHostName()))
			{
				return;
			}
			try
			{
				recordDeath.Invoke(null, new object[1] { val });
				recordedCharacters[rpc] = data.m_targetZDO;
			}
			catch (Exception ex)
			{
				logger.LogError((object)("Could not record death: " + ex.GetBaseException().Message));
			}
		}

		private static bool StoreDeath(object collection, string playerName, string playerHostName, Vector3 pos)
		{
			//IL_002f: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			if (collection != deaths.GetValue(database.GetValue(null)))
			{
				return true;
			}
			object obj = createDeathRecord.Invoke(new object[5] { playerName, playerHostName, pos.x, pos.y, pos.z });
			insertDeathRecord.Invoke(collection, new object[1] { obj });
			return false;
		}

		private static void ForgetPeer(ZNetPeer peer)
		{
			if (peer != null)
			{
				recordedCharacters.Remove(peer.m_rpc);
			}
		}

		private static void ClearDeaths()
		{
			recordedCharacters.Clear();
		}

		internal static void Tick()
		{
			if (logger == null || running || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated() || DateTime.UtcNow < nextCheckUtc)
			{
				return;
			}
			nextCheckUtc = DateTime.UtcNow.AddMinutes(1.0);
			string path = Path.Combine(Paths.BepInExRootPath, "death-leaderboard");
			string path2 = Path.Combine(path, ZNet.instance.GetWorldUID().ToString(CultureInfo.InvariantCulture) + (Plugin.DeathLeaderboardDryRun.Value ? "-preview.dat" : ".dat"));
			bool preview = Plugin.DeathLeaderboardDryRun.Value;
			running = true;
			Task.Run(async delegate
			{
				try
				{
					await Check(path2, preview);
				}
				catch (Exception ex)
				{
					logger.LogError((object)("Death leaderboard failed: " + ex.GetBaseException().Message));
					nextCheckUtc = DateTime.UtcNow.AddMinutes(5.0);
				}
				finally
				{
					running = false;
				}
			});
		}

		private static async Task Check(string path, bool preview)
		{
			object value = configuration.GetValue(null);
			if (!(bool)Read(value, "CollectStatsEnabled") || !(bool)Read(value, "StatsDeathEnabled"))
			{
				throw new InvalidOperationException("Enable DiscordConnector player statistics and death statistics before reporting.");
			}
			object value2 = deaths.GetValue(database.GetValue(null));
			if (value2 == null)
			{
				throw new InvalidOperationException("DiscordConnector death database is not initialized.");
			}
			DateTime now = DateTime.UtcNow;
			DeliveryState state = (File.Exists(path) ? JsonConvert.DeserializeObject<DeliveryState>(File.ReadAllText(path)) : new DeliveryState
			{
				RecordingSinceUtc = now
			});
			if (state == null || state.RecordingSinceUtc == default(DateTime))
			{
				throw new InvalidDataException("Invalid death leaderboard state; restore its backup before reporting.");
			}
			if (!File.Exists(path))
			{
				Save(path, state);
			}
			DateTime end = LatestDeadline(now);
			if (!announced)
			{
				string text = Compose(value2, end);
				logger.LogInfo((object)("Death leaderboard database readable; first full report after " + state.RecordingSinceUtc.AddHours(24.0).ToString("O") + "."));
				if (preview)
				{
					logger.LogInfo((object)("Death leaderboard preview (not delivered):\n" + text));
				}
				announced = true;
			}
			if (state.PendingUtc != default(DateTime))
			{
				SkipUncertain(path, state, "was interrupted by a server stop");
			}
			if (end <= state.CompletedUtc || end.AddHours(-24.0) < state.RecordingSinceUtc || now < state.RetryAfterUtc)
			{
				return;
			}
			string text2 = Compose(value2, end);
			if (preview)
			{
				logger.LogInfo((object)("Death leaderboard preview (not delivered):\n" + text2));
			}
			else
			{
				if (!Uri.TryCreate((string)Read(Read(value, "PrimaryWebhook"), "Url"), UriKind.Absolute, out Uri result) || result.Scheme != "https" || (result.Host != "discord.com" && result.Host != "discordapp.com") || !Regex.IsMatch(result.AbsolutePath, "^/api(?:/v[0-9]+)?/webhooks/[0-9]+/[A-Za-z0-9_-]+$"))
				{
					throw new InvalidOperationException("Configure a valid DiscordConnector primary Discord webhook before reporting.");
				}
				UriBuilder uriBuilder = new UriBuilder(result)
				{
					Query = "wait=true"
				};
				state.PendingUtc = end;
				state.PendingContent = text2;
				Save(path, state);
				using HttpClient client = new HttpClient(new HttpClientHandler
				{
					AllowAutoRedirect = false
				})
				{
					Timeout = TimeSpan.FromSeconds(30.0)
				};
				using StringContent body = new StringContent(JsonConvert.SerializeObject((object)new
				{
					content = text2,
					allowed_mentions = new
					{
						parse = new string[0]
					}
				}), Encoding.UTF8, "application/json");
				HttpResponseMessage httpResponseMessage;
				try
				{
					httpResponseMessage = await client.PostAsync(uriBuilder.Uri, body);
				}
				catch (Exception ex)
				{
					if (NotSent(ex))
					{
						Retry(path, state, now.AddMinutes(15.0), "Discord could not be reached (" + ex.GetType().Name + ")");
					}
					else
					{
						SkipUncertain(path, state, "got no answer from Discord (" + ex.GetType().Name + ")");
					}
					return;
				}
				using (httpResponseMessage)
				{
					int statusCode = (int)httpResponseMessage.StatusCode;
					if (statusCode == 429)
					{
						HttpResponseMessage response = httpResponseMessage;
						double value3 = RetryAfterSeconds(response, await httpResponseMessage.Content.ReadAsStringAsync());
						Retry(path, state, now.AddSeconds(value3), "Discord rate limited the report");
						return;
					}
					if (statusCode >= 500)
					{
						SkipUncertain(path, state, "failed with HTTP " + statusCode + " from Discord");
						return;
					}
					if (!httpResponseMessage.IsSuccessStatusCode)
					{
						Retry(path, state, now.AddMinutes(15.0), "Discord refused it with HTTP " + statusCode + "; check the webhook");
						return;
					}
				}
			}
			state.CompletedUtc = end;
			state.PendingUtc = default(DateTime);
			state.PendingContent = null;
			Save(path, state);
			logger.LogInfo((object)("Death leaderboard " + (preview ? "previewed" : "delivered") + " for " + end.ToString("O")));
		}

		private static void Retry(string path, DeliveryState state, DateTime retryAfterUtc, string reason)
		{
			state.PendingUtc = default(DateTime);
			state.PendingContent = null;
			state.RetryAfterUtc = retryAfterUtc;
			Save(path, state);
			logger.LogWarning((object)("Death leaderboard not delivered: " + reason + ". Retrying after " + retryAfterUtc.ToString("O") + "."));
		}

		private static void SkipUncertain(string path, DeliveryState state, string reason)
		{
			logger.LogWarning((object)("Death leaderboard delivery for " + state.PendingUtc.ToString("O") + " " + reason + "; it will not be resent, to avoid a duplicate. If Discord does not show it, post this text manually:\n" + state.PendingContent));
			if (state.PendingUtc > state.CompletedUtc)
			{
				state.CompletedUtc = state.PendingUtc;
			}
			state.PendingUtc = default(DateTime);
			state.PendingContent = null;
			Save(path, state);
		}

		private static bool NotSent(Exception error)
		{
			for (Exception ex = error; ex != null; ex = ex.InnerException)
			{
				if (ex is AuthenticationException)
				{
					return true;
				}
				if (ex is WebException ex2 && (ex2.Status == WebExceptionStatus.NameResolutionFailure || ex2.Status == WebExceptionStatus.ProxyNameResolutionFailure || ex2.Status == WebExceptionStatus.ConnectFailure || ex2.Status == WebExceptionStatus.SecureChannelFailure || ex2.Status == WebExceptionStatus.TrustFailure))
				{
					return true;
				}
				if (ex is SocketException ex3 && (ex3.SocketErrorCode == SocketError.HostNotFound || ex3.SocketErrorCode == SocketError.TryAgain || ex3.SocketErrorCode == SocketError.NoData || ex3.SocketErrorCode == SocketError.ConnectionRefused || ex3.SocketErrorCode == SocketError.NetworkDown || ex3.SocketErrorCode == SocketError.NetworkUnreachable || ex3.SocketErrorCode == SocketError.HostUnreachable))
				{
					return true;
				}
			}
			return false;
		}

		private static double RetryAfterSeconds(HttpResponseMessage response, string body)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Invalid comparison between Unknown and I4
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			double num = (response.Headers.RetryAfter?.Delta?.TotalSeconds).GetValueOrDefault();
			try
			{
				JToken val = JObject.Parse(body)["retry_after"];
				if (val != null && ((int)val.Type == 7 || (int)val.Type == 6))
				{
					num = Math.Max(num, (double)val);
				}
			}
			catch (JsonReaderException)
			{
			}
			return Math.Max(300.0, num);
		}

		internal static DateTime LatestDeadline(DateTime utcNow)
		{
			DateTime dateTime = TimeZoneInfo.ConvertTimeFromUtc(utcNow, warsaw);
			DateTime dateTime2 = DateTime.SpecifyKind(dateTime.Date.AddHours(6.0), DateTimeKind.Unspecified);
			if (dateTime < dateTime2)
			{
				dateTime2 = dateTime2.AddDays(-1.0);
			}
			return TimeZoneInfo.ConvertTimeToUtc(dateTime2, warsaw);
		}

		private static string Compose(object collection, DateTime end)
		{
			DateTime dateTime = end.AddHours(-24.0);
			Dictionary<string, Ranking> dictionary = new Dictionary<string, Ranking>(StringComparer.Ordinal);
			foreach (object item in (IEnumerable)findAll.Invoke(collection, null))
			{
				DateTime dateTime2 = ((DateTime)recordDate.GetValue(item)).ToUniversalTime();
				if (!(dateTime2 < dateTime) && !(dateTime2 >= end))
				{
					string text = (string)recordPlayer.GetValue(item);
					if (string.IsNullOrEmpty(text))
					{
						throw new InvalidDataException("Death record has no player identity.");
					}
					if (!dictionary.TryGetValue(text, out var value))
					{
						Ranking obj = new Ranking
						{
							PlayerId = text
						};
						value = obj;
						dictionary[text] = obj;
					}
					value.Count++;
					if (dateTime2 >= value.LatestUtc)
					{
						value.LatestUtc = dateTime2;
						value.Name = PlainName((string)recordName.GetValue(item));
					}
				}
			}
			StringBuilder stringBuilder = new StringBuilder("Ranking zgonów — ostatnie 24 godziny\n\n");
			List<Ranking> list = dictionary.Values.OrderByDescending((Ranking row) => row.Count).ThenBy<Ranking, string>((Ranking row) => row.Name, StringComparer.Ordinal).ThenBy<Ranking, string>((Ranking row) => row.PlayerId, StringComparer.Ordinal)
				.ToList();
			if (list.Count == 0)
			{
				stringBuilder.Append("Nikt nie zginął.");
			}
			int num = 0;
			int num2 = -1;
			for (int num3 = 0; num3 < list.Count; num3++)
			{
				Ranking ranking = list[num3];
				if (ranking.Count != num2)
				{
					num = num3 + 1;
				}
				num2 = ranking.Count;
				string text2 = $"{num}. {ranking.Name}: {ranking.Count}\n";
				if (stringBuilder.Length + text2.Length > 1850)
				{
					stringBuilder.Append("Pozostali gracze: ").Append(list.Count - num3).Append(".\n");
					break;
				}
				stringBuilder.Append(text2);
			}
			stringBuilder.Append("\nŁącznie zgonów: ").Append(list.Sum((Ranking row) => row.Count));
			return DiscordSystemMessages.Box(stringBuilder.ToString());
		}

		private static string PlainName(string name)
		{
			name = Regex.Replace(name ?? "", "<[^>]*>", "");
			name = new string(name.Where((char character) => !char.IsControl(character) && char.GetUnicodeCategory(character) != UnicodeCategory.Format).ToArray()).Replace('`', '\'');
			name = Regex.Replace(name, "\\s+", " ").Trim();
			if (name.Length == 0)
			{
				return "Gracz";
			}
			if (StringInfo.ParseCombiningCharacters(name).Length <= 60)
			{
				return name;
			}
			return new StringInfo(name).SubstringByTextElements(0, 60);
		}

		private static object Read(object instance, string name)
		{
			return AccessTools.Property(instance.GetType(), name)?.GetValue(instance) ?? throw new MissingMemberException("DiscordConnector setting unavailable: " + name);
		}

		private static void Save(string path, DeliveryState state)
		{
			Directory.CreateDirectory(Path.GetDirectoryName(path));
			string text = path + ".tmp";
			byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject((object)state, (Formatting)1));
			using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None))
			{
				fileStream.Write(bytes, 0, bytes.Length);
				fileStream.Flush(flushToDisk: true);
			}
			if (File.Exists(path))
			{
				File.Replace(text, path, null);
			}
			else
			{
				File.Move(text, path);
			}
		}
	}
	internal static class DeathMessageFormatting
	{
		private const string PlayerColor = "<color=#FF5555>";

		private static MethodInfo cacheEntryOf;

		private static PropertyInfo untranslatedNameOf;

		private static ManualLogSource logger;

		internal static void Initialize(H