Decompiled source of ReviveAll v1.0.0

ReviveAll.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ReviveAll
{
	[BepInPlugin("reviveall", "Revive All", "1.6.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal const string ItemAssetName = "Item Revive All";

		internal const string ItemDisplayName = "Revive";

		internal const string StartHealthItemAssetName = "Item Revive Start Health";

		internal const string StartHealthItemDisplayName = "Revive Start Health";

		private const string TemplateItemName = "Item Upgrade Player Grab Range";

		internal static ConfigEntry<int> MaxRevives;

		internal static ConfigEntry<int> ReviveHealth;

		internal static ConfigEntry<int> ShopPrice;

		internal static ConfigEntry<int> ShopPrice2;

		internal static ConfigEntry<string> TemplateItem;

		internal static ConfigEntry<string> ItemColor;

		internal static bool PromptOpen = false;

		internal static bool BypassPatch = false;

		internal static float IgnoreUntil = 0f;

		internal static object[] PendingArgs;

		internal static RunManager PendingRunManager;

		private const string UsedKey = "reviveAllUsed";

		private const string BonusKey = "reviveAllBonus";

		private const string StartHealthBonusKey = "reviveAllStartHealthBonus";

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

		internal static bool Cover = false;

		private static Texture2D blackTex;

		private float coverTimer;

		private float syncTimer;

		private int lastSentLeft = -1;

		private static GUIStyle smallStyle;

		private static GUIStyle bigStyle;

		private static GUIStyle infoStyle;

		private static Item reviveItem;

		private static Item startHealthItem;

		private static int registerAttempts;

		private static bool registering;

		private static bool boundLogged;

		private static bool startHealthBoundLogged;

		internal static int UsedRevives
		{
			get
			{
				return GetStat("reviveAllUsed");
			}
			set
			{
				SetStat("reviveAllUsed", value);
			}
		}

		internal static int Bonus
		{
			get
			{
				return GetStat("reviveAllBonus");
			}
			set
			{
				SetStat("reviveAllBonus", value);
			}
		}

		internal static int StartHealthBonus
		{
			get
			{
				return GetStat("reviveAllStartHealthBonus");
			}
			set
			{
				SetStat("reviveAllStartHealthBonus", value);
			}
		}

		internal static int RevivesLeft => Mathf.Max(0, MaxRevives.Value + Bonus - UsedRevives);

		private static int GetStat(string key)
		{
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance != (Object)null && instance.runStats != null)
			{
				if (!instance.runStats.TryGetValue(key, out var value))
				{
					return 0;
				}
				return value;
			}
			if (!fallbackStats.TryGetValue(key, out var value2))
			{
				return 0;
			}
			return value2;
		}

		private static void SetStat(string key, int value)
		{
			fallbackStats[key] = value;
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance != (Object)null && instance.runStats != null)
			{
				instance.runStats[key] = value;
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)$"Run-Stat {key} = {value}");
				}
			}
		}

		internal static void ResetCounter()
		{
			fallbackStats.Clear();
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance != (Object)null && instance.runStats != null)
			{
				instance.runStats.Remove("reviveAllUsed");
				instance.runStats.Remove("reviveAllBonus");
				instance.runStats.Remove("reviveAllStartHealthBonus");
			}
		}

		private void Awake()
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			MaxRevives = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxRevives", 3, "Mit so vielen Wiederbelebungen startet ein Run (im Shop kannst du weitere kaufen).");
			ReviveHealth = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ReviveHealth", 50, new ConfigDescription("Leben, mit dem ein Spieler wiederbelebt wird (wird auf die maximale Gesundheit begrenzt).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
			ShopPrice = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "ShopPrice", 1, new ConfigDescription("Preis des Shop-Items in Tausend ($). 4 = $4K.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
			ShopPrice2 = ((BaseUnityPlugin)this).Config.Bind<int>("Shop", "ShopPrice2", 1, new ConfigDescription("Preis des Shop-Items in Tausend ($). 4 = $4K.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 1000), Array.Empty<object>()));
			TemplateItem = ((BaseUnityPlugin)this).Config.Bind<string>("Shop", "TemplateItem", "Item Upgrade Player Grab Range", "Name des vorhandenen Items, das als Vorlage für das Shop-Item kopiert wird. Zum Testen z. B. 'Item Upgrade Player Grab Range'.");
			ItemColor = ((BaseUnityPlugin)this).Config.Bind<string>("Shop", "ItemColor", "#4DFF80", "Farbe des Shop-Items (Hex, z. B. #4DFF80). Leer lassen, um das Aussehen der Vorlage unverändert zu lassen.");
			new Harmony("reviveall").PatchAll();
			((MonoBehaviour)this).StartCoroutine(RegisterReviveItem());
			Log.LogInfo((object)("Revive All 1.6.0 geladen. Config: " + ((BaseUnityPlugin)this).Config.ConfigFilePath));
		}

		private void Update()
		{
			SyncRevives();
			if (Input.GetKeyDown((KeyCode)290))
			{
				try
				{
					DumpInfo();
				}
				catch (Exception ex)
				{
					Log.LogError((object)("Dump fehlgeschlagen: " + ex));
				}
			}
			if (Input.GetKeyDown((KeyCode)291))
			{
				try
				{
					ExportTemplateTextures();
				}
				catch (Exception ex2)
				{
					Log.LogError((object)("Textur-Export fehlgeschlagen: " + ex2));
				}
			}
			if (Cover)
			{
				coverTimer += Time.deltaTime;
				if (coverTimer > 12f)
				{
					Cover = false;
					coverTimer = 0f;
				}
			}
			else
			{
				coverTimer = 0f;
			}
			if (PromptOpen)
			{
				if (Input.GetKeyDown((KeyCode)121) || Input.GetKeyDown((KeyCode)122))
				{
					Accept();
				}
				else if (Input.GetKeyDown((KeyCode)110))
				{
					Decline();
				}
			}
		}

		private static void EnsureStyles()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0031: Expected O, but got Unknown
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0095: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
			if (bigStyle == null)
			{
				smallStyle = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4,
					richText = true
				};
				bigStyle = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4,
					richText = true
				};
				infoStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					richText = true
				};
				smallStyle.normal.textColor = new Color(1f, 0.35f, 0.35f);
				bigStyle.normal.textColor = Color.white;
				infoStyle.normal.textColor = Color.white;
			}
		}

		private void OnGUI()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0071: 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_0036: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type == 7 && (Cover || PromptOpen))
			{
				if ((Object)(object)blackTex == (Object)null)
				{
					blackTex = new Texture2D(1, 1);
					blackTex.SetPixel(0, 0, Color.black);
					blackTex.Apply();
				}
				GUI.depth = -1000;
				GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)blackTex);
				if (PromptOpen)
				{
					EnsureStyles();
					float num = Screen.width;
					float num2 = (float)Screen.height / 2f;
					float num3 = (float)Screen.height / 100f;
					smallStyle.fontSize = Mathf.RoundToInt(num3 * 3f);
					bigStyle.fontSize = Mathf.RoundToInt(num3 * 7f);
					infoStyle.fontSize = Mathf.RoundToInt(num3 * 3.5f);
					GUI.Label(new Rect(0f, num2 - num3 * 18f, num, num3 * 6f), "ALL PLAYERS ARE DEAD", smallStyle);
					GUI.Label(new Rect(0f, num2 - num3 * 10f, num, num3 * 10f), "Revive everyone?", bigStyle);
					GUI.Label(new Rect(0f, num2 + num3 * 2f, num, num3 * 6f), "Revives left: " + RevivesLeft, infoStyle);
					GUI.Label(new Rect(0f, num2 + num3 * 10f, num, num3 * 6f), "<color=#6cff6c>[Y]</color> Yes        <color=#ff5050>[N]</color> No", infoStyle);
				}
			}
		}

		private void Accept()
		{
			if (PromptOpen)
			{
				PromptOpen = false;
				if (ReviveEveryone() == 0)
				{
					Log.LogError((object)"Niemand wiederbelebt, normaler Game-Over läuft.");
					RunOriginalChangeLevel();
				}
				else
				{
					UsedRevives++;
					IgnoreUntil = Time.time + 5f;
					Log.LogInfo((object)$"Wiederbelebung benutzt, übrig: {RevivesLeft}");
				}
				PendingArgs = null;
				PendingRunManager = null;
			}
		}

		private void Decline()
		{
			PromptOpen = false;
			ResetCounter();
			RunOriginalChangeLevel();
			PendingArgs = null;
			PendingRunManager = null;
		}

		private static void RunOriginalChangeLevel()
		{
			if ((Object)(object)PendingRunManager == (Object)null || PendingArgs == null)
			{
				return;
			}
			BypassPatch = true;
			try
			{
				AccessTools.Method(typeof(RunManager), "ChangeLevel", (Type[])null, (Type[])null).Invoke(PendingRunManager, PendingArgs);
			}
			finally
			{
				BypassPatch = false;
			}
		}

		private static int ReviveEveryone()
		{
			List<PlayerAvatar> list = new List<PlayerAvatar>(Object.FindObjectsOfType<PlayerAvatar>(true));
			if (list.Count == 0)
			{
				try
				{
					object obj = AccessTools.Field(typeof(GameDirector), "instance")?.GetValue(null);
					List<PlayerAvatar> list2 = ((obj != null) ? (AccessTools.Field(typeof(GameDirector), "PlayerList")?.GetValue(obj) as List<PlayerAvatar>) : null);
					if (list2 != null)
					{
						list.AddRange(list2);
					}
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("GameDirector-Fallback fehlgeschlagen: " + ex.Message));
				}
			}
			Log.LogInfo((object)$"Gefundene Spieler: {list.Count}");
			if (list.Count > 0)
			{
				Cover = true;
			}
			int num = 0;
			foreach (PlayerAvatar item in list)
			{
				if (!((Object)(object)item == (Object)null))
				{
					try
					{
						item.Revive(false);
						num++;
						Log.LogInfo((object)("Revive aufgerufen für " + ((Object)item).name));
					}
					catch (Exception ex2)
					{
						Log.LogError((object)("Revive fehlgeschlagen: " + ex2));
					}
				}
			}
			if (num > 0 && (Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(TeleportWithCover(list));
			}
			else
			{
				Cover = false;
			}
			return num;
		}

		private static bool TryGetTruckSpawn(out Vector3 pos, out Quaternion rot)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			pos = Vector3.zero;
			rot = Quaternion.identity;
			Assembly assembly = typeof(PlayerAvatar).Assembly;
			string[] array = new string[3] { "SpawnPoint", "PlayerSpawnPoint", "TruckSafetySpawnPoint" };
			foreach (string text in array)
			{
				Type type = assembly.GetType(text);
				if (type == null || !typeof(Component).IsAssignableFrom(type))
				{
					continue;
				}
				Object[] array2 = Resources.FindObjectsOfTypeAll(type);
				foreach (Object obj in array2)
				{
					Component val = (Component)(object)((obj is Component) ? obj : null);
					if (!((Object)(object)val == (Object)null))
					{
						Scene scene = val.gameObject.scene;
						if (((Scene)(ref scene)).IsValid())
						{
							pos = val.transform.position;
							rot = val.transform.rotation;
							Log.LogInfo((object)$"Spawnpunkt: {text} bei {pos}");
							return true;
						}
					}
				}
			}
			Log.LogWarning((object)"Kein Truck-Spawnpunkt gefunden.");
			return false;
		}

		private static IEnumerator TeleportToTruck(List<PlayerAvatar> avatars)
		{
			if (!TryGetTruckSpawn(out var basePos, out var rot))
			{
				yield break;
			}
			MethodInfo spawn = typeof(PlayerAvatar).GetMethod("Spawn", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
			{
				typeof(Vector3),
				typeof(Quaternion)
			}, null);
			if (spawn == null)
			{
				Log.LogError((object)"PlayerAvatar.Spawn(Vector3, Quaternion) nicht gefunden.");
				yield break;
			}
			HashSet<PlayerAvatar> done = new HashSet<PlayerAvatar>();
			float timeout = Time.time + 10f;
			while (Time.time < timeout && done.Count < avatars.Count)
			{
				yield return (object)new WaitForSeconds(0.25f);
				int num = 0;
				foreach (PlayerAvatar avatar in avatars)
				{
					int num2 = num++;
					if (!((Object)(object)avatar == (Object)null) && !done.Contains(avatar))
					{
						Vector3 val = basePos + new Vector3((float)(num2 % 2) * 1.2f, 0.2f, (float)(num2 / 2) * 1.2f);
						float num3 = Vector3.Distance(((Component)avatar).transform.position, val);
						if (num3 <= 3f)
						{
							done.Add(avatar);
							Log.LogInfo((object)$"Am Truck angekommen: {((Object)avatar).name} ({num3:F1} m)");
						}
						else
						{
							spawn.Invoke(avatar, new object[2] { val, rot });
						}
					}
				}
			}
			if (done.Count < avatars.Count)
			{
				Log.LogWarning((object)"Nicht alle Spieler konnten zum Truck gesetzt werden.");
			}
		}

		private static IEnumerator TeleportWithCover(List<PlayerAvatar> avatars)
		{
			yield return ((MonoBehaviour)Instance).StartCoroutine(TeleportToTruck(avatars));
			yield return (object)new WaitForSeconds(0.4f);
			ApplyReviveHealth(avatars);
			Cover = false;
		}

		private static void ApplyReviveHealth(List<PlayerAvatar> avatars)
		{
			foreach (PlayerAvatar avatar in avatars)
			{
				if ((Object)(object)avatar == (Object)null)
				{
					continue;
				}
				try
				{
					object obj = AccessTools.Field(typeof(PlayerAvatar), "playerHealth")?.GetValue(avatar);
					if (obj == null)
					{
						Log.LogError((object)"PlayerAvatar.playerHealth nicht gefunden.");
						continue;
					}
					Type type = obj.GetType();
					FieldInfo fieldInfo = AccessTools.Field(type, "health");
					FieldInfo fieldInfo2 = AccessTools.Field(type, "maxHealth");
					if (fieldInfo == null || fieldInfo.FieldType != typeof(int))
					{
						Log.LogError((object)"Feld 'health' (int) nicht gefunden. Vorhandene Felder:");
						FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						foreach (FieldInfo fieldInfo3 in fields)
						{
							Log.LogInfo((object)("  " + type.Name + "." + fieldInfo3.Name + " (" + fieldInfo3.FieldType.Name + ")"));
						}
					}
					else
					{
						int num = ((fieldInfo2 != null && fieldInfo2.FieldType == typeof(int)) ? ((int)fieldInfo2.GetValue(obj)) : int.MaxValue);
						int num2 = Mathf.Clamp(ReviveHealth.Value + StartHealthBonus, 1, num);
						fieldInfo.SetValue(obj, num2);
						Log.LogInfo((object)$"Leben gesetzt auf {num2} (max {num}) für {((Object)avatar).name}");
					}
				}
				catch (Exception ex)
				{
					Log.LogError((object)("Leben setzen fehlgeschlagen: " + ex));
				}
			}
		}

		private IEnumerator RegisterReviveItem()
		{
			float timeout = Time.realtimeSinceStartup + 180f;
			while (Time.realtimeSinceStartup < timeout)
			{
				if (TryRegister())
				{
					yield break;
				}
				yield return (object)new WaitForSeconds(0.5f);
			}
			Log.LogError((object)"Shop-Item wurde nicht registriert (Timeout).");
		}

		internal static bool TryRegister()
		{
			if (registering)
			{
				return false;
			}
			registering = true;
			try
			{
				StatsManager instance = StatsManager.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return false;
				}
				if (!(AccessTools.Field(typeof(StatsManager), "itemDictionary")?.GetValue(instance) is IDictionary { Count: not 0 } dictionary))
				{
					return false;
				}
				if ((Object)(object)reviveItem == (Object)null || (Object)(object)startHealthItem == (Object)null)
				{
					if (registerAttempts >= 5)
					{
						return false;
					}
					registerAttempts++;
					if ((Object)(object)reviveItem == (Object)null)
					{
						reviveItem = CreateShopItem(dictionary, "Item Revive All", "Revive", "Adds one revive for the whole team.", (float)ShopPrice.Value * 1000f, isStartHealthItem: false);
					}
					if ((Object)(object)startHealthItem == (Object)null)
					{
						startHealthItem = CreateShopItem(dictionary, "Item Revive Start Health", "Revive Start Health", "Adds 10 HP to the health players have when revived.", (float)ShopPrice2.Value * 1000f, isStartHealthItem: true);
					}
					if ((Object)(object)reviveItem == (Object)null || (Object)(object)startHealthItem == (Object)null)
					{
						return false;
					}
				}
				if (!AddToCatalog(dictionary, "Item Revive All", reviveItem))
				{
					return false;
				}
				if (!AddToCatalog(dictionary, "Item Revive Start Health", startHealthItem))
				{
					return false;
				}
				if (!boundLogged)
				{
					boundLogged = true;
					Log.LogInfo((object)"Shop-Item 'Revive' ist im Item-Katalog.");
				}
				if (!startHealthBoundLogged)
				{
					startHealthBoundLogged = true;
					Log.LogInfo((object)"Shop-Item 'Revive Start Health' ist im Item-Katalog.");
				}
				return true;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Shop-Item registrieren fehlgeschlagen: " + ex));
				return false;
			}
			finally
			{
				registering = false;
			}
		}

		private static bool AddToCatalog(IDictionary dict, string assetName, Item item)
		{
			Item val = (Item)(dict.Contains(assetName) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)item)
			{
				Log.LogWarning((object)("Konflikt: Im Katalog liegt schon ein anderes Item namens " + assetName));
				return false;
			}
			dict[assetName] = item;
			return true;
		}

		private static Item CreateShopItem(IDictionary dict, string assetName, string displayName, string description, float price, bool isStartHealthItem)
		{
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Expected O, but got Unknown
			string value = TemplateItem.Value;
			Item val = (Item)(dict.Contains(value) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)("Vorlage-Item nicht gefunden: " + value + ". Vorhandene Items:"));
				foreach (object key in dict.Keys)
				{
					Log.LogInfo((object)("  " + key));
				}
				return null;
			}
			Log.LogInfo((object)("Vorlage-Item: " + value));
			Item val2 = Object.Instantiate<Item>(val);
			((Object)val2).name = assetName;
			SetMember(val2, "itemName", displayName);
			SetMember(val2, "itemNameLocalized", null);
			SetMember(val2, "description", description);
			SetMember(val2, "maxAmount", 99);
			SetMember(val2, "maxAmountInShop", 2);
			SetMember(val2, "minPlayerCount", 1);
			SetMember(val2, "disabled", false);
			SetMember(val2, "maxPurchase", false);
			SetMember(val2, "physicalItem", true);
			FieldInfo fieldInfo = AccessTools.Field(typeof(Item), "value");
			object? obj = fieldInfo?.GetValue(val);
			Object val3 = (Object)((obj is Object) ? obj : null);
			if (val3 != (Object)null)
			{
				Log.LogInfo((object)string.Format("Vorlage-Preis: min {0} max {1}", GetMember(val3, "valueMin"), GetMember(val3, "valueMax")));
				Object val4 = Object.Instantiate(val3);
				SetMember(val4, "valueMin", price);
				SetMember(val4, "valueMax", price);
				fieldInfo.SetValue(val2, val4);
			}
			else
			{
				Log.LogWarning((object)"Vorlage hat kein 'value', Preis bleibt wie bei der Vorlage.");
			}
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(Item), "colorPreset");
			object? obj2 = fieldInfo2?.GetValue(val);
			Object val5 = (Object)((obj2 is Object) ? obj2 : null);
			if (val5 != (Object)null)
			{
				Object val6 = Object.Instantiate(val5);
				SetMember(val6, "colorMain", (object)new Color(0.3f, 1f, 0.5f));
				SetMember(val6, "colorLight", (object)new Color(0.3f, 1f, 0.5f));
				SetMember(val6, "colorDark", (object)new Color(0.18f, 0.6f, 0.3f));
				fieldInfo2.SetValue(val2, val6);
			}
			FieldInfo fieldInfo3 = AccessTools.Field(typeof(Item), "prefab");
			GameObject prefabFromRef = GetPrefabFromRef(fieldInfo3?.GetValue(val));
			if ((Object)(object)prefabFromRef == (Object)null)
			{
				Log.LogError((object)"Prefab der Vorlage nicht gefunden.");
				return null;
			}
			GameObject val7 = new GameObject("ReviveAll_PrefabHolder");
			val7.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val7);
			GameObject val8 = Object.Instantiate<GameObject>(prefabFromRef, val7.transform, false);
			val8.SetActive(true);
			((Object)val8).name = assetName;
			ItemAttributes component = val8.GetComponent<ItemAttributes>();
			if ((Object)(object)component == (Object)null)
			{
				Log.LogError((object)"Geklontes Prefab hat kein ItemAttributes.");
				return null;
			}
			SetMember(component, "item", val2);
			SetMember(component, "itemName", displayName);
			SetMember(component, "promptName", displayName);
			SetMember(component, "itemAssetName", assetName);
			ItemHealthPack component2 = val8.GetComponent<ItemHealthPack>();
			if ((Object)(object)component2 != (Object)null)
			{
				SetMember(component2, "healAmount", 0);
			}
			if (!ApplyCardTexture(val8, isStartHealthItem))
			{
				TintClone(val8, isStartHealthItem ? "#59B8FF" : ItemColor.Value);
			}
			MonoBehaviour[] components = val8.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val9 in components)
			{
				if (!((Object)(object)val9 == (Object)null))
				{
					string name = ((object)val9).GetType().Name;
					if (name.StartsWith("ItemUpgrade", StringComparison.Ordinal))
					{
						Log.LogInfo((object)("Entferne Upgrade-Komponente aus dem Klon: " + name));
						Object.DestroyImmediate((Object)(object)val9);
					}
				}
			}
			MethodInfo methodInfo = AccessTools.TypeByName("REPOLib.Modules.Items")?.GetMethod("RegisterItem", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(ItemAttributes) }, null);
			if (methodInfo == null)
			{
				Log.LogError((object)"REPOLib.Modules.Items.RegisterItem(ItemAttributes) nicht gefunden.");
				return null;
			}
			List<Action> list = PreserveExistingStats(assetName);
			object obj3;
			try
			{
				obj3 = methodInfo.Invoke(null, new object[1] { component });
			}
			finally
			{
				foreach (Action item in list)
				{
					item();
				}
			}
			if (obj3 == null)
			{
				Log.LogError((object)"REPOLib hat keine PrefabRef geliefert.");
				return null;
			}
			fieldInfo3.SetValue(val2, obj3);
			Log.LogInfo((object)("Shop-Item '" + displayName + "' bei REPOLib registriert."));
			return val2;
		}

		private static Texture2D LoadTexture(string path)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
			MethodInfo methodInfo = AccessTools.TypeByName("UnityEngine.ImageConversion")?.GetMethod("LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			});
			if (methodInfo == null)
			{
				Log.LogError((object)"ImageConversion.LoadImage nicht gefunden.");
				return null;
			}
			if (!(bool)methodInfo.Invoke(null, new object[2]
			{
				val,
				File.ReadAllBytes(path)
			}))
			{
				Log.LogWarning((object)("Bild konnte nicht gelesen werden: " + path));
				return null;
			}
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			return val;
		}

		private static void LogMaterials(GameObject clone)
		{
			Log.LogInfo((object)"Materialien des Klons:");
			Renderer[] componentsInChildren = clone.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val == (Object)null || ((object)val).GetType().Name == "ParticleSystemRenderer")
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				foreach (Material val2 in sharedMaterials)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						Texture mainTexture = val2.mainTexture;
						Log.LogInfo((object)("  " + ((Object)val).name + ": Material '" + ((Object)val2).name + "' Shader '" + ((Object)val2.shader).name + "' Textur " + (((Object)(object)mainTexture != (Object)null) ? $"'{((Object)mainTexture).name}' {mainTexture.width}x{mainTexture.height}" : "-")));
					}
				}
			}
		}

		private static bool ApplyCardTexture(GameObject clone, bool isStartHealthItem)
		{
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			LogMaterials(clone);
			string? directoryName = Path.GetDirectoryName(((BaseUnityPlugin)Instance).Info.Location);
			string path = (isStartHealthItem ? "revivestarthealth.png" : "revive.png");
			string text = Path.Combine(directoryName, path);
			if (!File.Exists(text))
			{
				Log.LogInfo((object)("Kein Kartenbild (optional): " + text));
				return false;
			}
			Texture2D val = LoadTexture(text);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			bool flag = false;
			int num = 0;
			Renderer[] componentsInChildren = clone.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || ((object)val2).GetType().Name == "ParticleSystemRenderer")
				{
					continue;
				}
				Material[] sharedMaterials = val2.sharedMaterials;
				foreach (Material val3 in sharedMaterials)
				{
					Texture val4 = (((Object)(object)val3 != (Object)null) ? val3.mainTexture : null);
					if (!((Object)(object)val4 == (Object)null))
					{
						float num2 = (float)val4.height / (float)val4.width;
						if (num2 >= 1.25f && num2 <= 1.8f)
						{
							flag = true;
						}
						num = Mathf.Max(num, val4.width * val4.height);
					}
				}
			}
			int num3 = 0;
			componentsInChildren = clone.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val5 in componentsInChildren)
			{
				if ((Object)(object)val5 == (Object)null || ((object)val5).GetType().Name == "ParticleSystemRenderer")
				{
					continue;
				}
				Material[] materials = val5.materials;
				Material[] sharedMaterials = materials;
				foreach (Material val6 in sharedMaterials)
				{
					Texture val7 = (((Object)(object)val6 != (Object)null) ? val6.mainTexture : null);
					if ((Object)(object)val7 == (Object)null)
					{
						continue;
					}
					float num4 = (float)val7.height / (float)val7.width;
					bool num5;
					if (!flag)
					{
						num5 = val7.width * val7.height == num;
					}
					else
					{
						if (!(num4 >= 1.25f))
						{
							continue;
						}
						num5 = num4 <= 1.8f;
					}
					if (num5)
					{
						val6.mainTexture = (Texture)(object)val;
						if (val6.HasProperty("_MainTex"))
						{
							val6.SetTexture("_MainTex", (Texture)(object)val);
						}
						if (val6.HasProperty("_BaseMap"))
						{
							val6.SetTexture("_BaseMap", (Texture)(object)val);
						}
						if (val6.HasProperty("_Color"))
						{
							val6.SetColor("_Color", Color.white);
						}
						if (val6.HasProperty("_BaseColor"))
						{
							val6.SetColor("_BaseColor", Color.white);
						}
						val6.mainTextureScale = Vector2.one;
						val6.mainTextureOffset = Vector2.zero;
						num3++;
					}
				}
				val5.materials = materials;
			}
			Log.LogInfo((object)("Kartenbild auf " + num3 + " Material(ien) gesetzt."));
			return num3 > 0;
		}

		private static void TintClone(GameObject clone, string hex)
		{
			//IL_00a5: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(hex))
			{
				return;
			}
			Color val = default(Color);
			if (!ColorUtility.TryParseHtmlString(hex, ref val))
			{
				Log.LogWarning((object)("ItemColor ist keine gültige Hex-Farbe: " + hex));
				return;
			}
			int num = 0;
			Renderer[] componentsInChildren = clone.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || ((object)val2).GetType().Name == "ParticleSystemRenderer")
				{
					continue;
				}
				Material[] materials = val2.materials;
				Material[] array = materials;
				foreach (Material val3 in array)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						if (val3.HasProperty("_Color"))
						{
							val3.SetColor("_Color", val);
						}
						if (val3.HasProperty("_BaseColor"))
						{
							val3.SetColor("_BaseColor", val);
						}
						if (val3.HasProperty("_EmissionColor"))
						{
							val3.SetColor("_EmissionColor", new Color(val.r * 0.6f, val.g * 0.6f, val.b * 0.6f, 1f));
						}
						num++;
					}
				}
				val2.materials = materials;
			}
			Log.LogInfo((object)(num + " Materialien eingefärbt (" + hex + ")."));
		}

		private static List<Action> PreserveExistingStats(string itemName)
		{
			List<Action> list = new List<Action>();
			StatsManager instance = StatsManager.instance;
			SortedDictionary<string, Dictionary<string, int>> sortedDictionary = (((Object)(object)instance != (Object)null) ? (AccessTools.Field(typeof(StatsManager), "dictionaryOfDictionaries")?.GetValue(instance) as SortedDictionary<string, Dictionary<string, int>>) : null);
			if (sortedDictionary == null)
			{
				return list;
			}
			foreach (KeyValuePair<string, Dictionary<string, int>> item in sortedDictionary)
			{
				if (!item.Key.StartsWith("item", StringComparison.Ordinal))
				{
					continue;
				}
				Dictionary<string, int> data = item.Value;
				int old;
				bool existed = data.TryGetValue(itemName, out old);
				list.Add(delegate
				{
					if (existed)
					{
						data[itemName] = old;
					}
					else
					{
						data.Remove(itemName);
					}
				});
			}
			return list;
		}

		private static GameObject GetPrefabFromRef(object r)
		{
			if (r == null)
			{
				return null;
			}
			Type type = r.GetType();
			string[] array = new string[2] { "Prefab", "prefab" };
			foreach (string text in array)
			{
				PropertyInfo property = type.GetProperty(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					object? value = property.GetValue(r);
					GameObject val = (GameObject)((value is GameObject) ? value : null);
					if (val != null)
					{
						return val;
					}
				}
				FieldInfo fieldInfo = AccessTools.Field(type, text);
				if (fieldInfo != null)
				{
					object? value2 = fieldInfo.GetValue(r);
					GameObject val2 = (GameObject)((value2 is GameObject) ? value2 : null);
					if (val2 != null)
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static void SetMember(object target, string name, object value)
		{
			if (target == null)
			{
				return;
			}
			FieldInfo fieldInfo = AccessTools.Field(target.GetType(), name);
			if (fieldInfo == null)
			{
				Log.LogWarning((object)("Feld '" + name + "' nicht gefunden in " + target.GetType().Name));
				return;
			}
			try
			{
				object value2 = value;
				if (value is IConvertible && fieldInfo.FieldType.IsPrimitive)
				{
					value2 = Convert.ChangeType(value, fieldInfo.FieldType);
				}
				fieldInfo.SetValue(target, value2);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Feld '" + name + "' setzen fehlgeschlagen: " + ex.Message));
			}
		}

		private static object GetMember(object target, string name)
		{
			if (target == null)
			{
				return null;
			}
			return AccessTools.Field(target.GetType(), name)?.GetValue(target);
		}

		private static void ExportTemplateTextures()
		{
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Expected O, but got Unknown
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			StatsManager instance = StatsManager.instance;
			IDictionary dictionary = (((Object)(object)instance != (Object)null) ? (AccessTools.Field(typeof(StatsManager), "itemDictionary")?.GetValue(instance) as IDictionary) : null);
			string value = TemplateItem.Value;
			Item val = (Item)((dictionary != null && dictionary.Contains(value)) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null)
			{
				Log.LogError((object)("Vorlage-Item nicht gefunden: " + value));
				return;
			}
			GameObject prefabFromRef = GetPrefabFromRef(AccessTools.Field(typeof(Item), "prefab")?.GetValue(val));
			if ((Object)(object)prefabFromRef == (Object)null)
			{
				Log.LogError((object)"Prefab der Vorlage nicht gefunden.");
				return;
			}
			MethodInfo methodInfo = AccessTools.TypeByName("UnityEngine.ImageConversion")?.GetMethod("EncodeToPNG", new Type[1] { typeof(Texture2D) });
			if (methodInfo == null)
			{
				Log.LogError((object)"ImageConversion.EncodeToPNG nicht gefunden.");
				return;
			}
			string text = Path.Combine(Paths.BepInExRootPath, "ReviveAll_textures");
			Directory.CreateDirectory(text);
			HashSet<Texture> hashSet = new HashSet<Texture>();
			int num = 0;
			Renderer[] componentsInChildren = prefabFromRef.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || ((object)val2).GetType().Name == "ParticleSystemRenderer")
				{
					continue;
				}
				Material[] sharedMaterials = val2.sharedMaterials;
				foreach (Material val3 in sharedMaterials)
				{
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					string[] texturePropertyNames = val3.GetTexturePropertyNames();
					foreach (string text2 in texturePropertyNames)
					{
						Texture texture = val3.GetTexture(text2);
						if (!((Object)(object)texture == (Object)null) && texture.width >= 2 && texture.height >= 2 && hashSet.Add(texture))
						{
							string text3 = Sanitize(value + "_" + ((Object)val2).name + "_" + ((Object)val3).name + "_" + text2 + "_" + ((Object)texture).name) + ".png";
							string path = Path.Combine(text, text3);
							try
							{
								RenderTexture temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
								Graphics.Blit(texture, temporary);
								RenderTexture active = RenderTexture.active;
								RenderTexture.active = temporary;
								Texture2D val4 = new Texture2D(texture.width, texture.height, (TextureFormat)4, false);
								val4.ReadPixels(new Rect(0f, 0f, (float)texture.width, (float)texture.height), 0, 0);
								val4.Apply();
								RenderTexture.active = active;
								RenderTexture.ReleaseTemporary(temporary);
								File.WriteAllBytes(path, (byte[])methodInfo.Invoke(null, new object[1] { val4 }));
								Object.Destroy((Object)(object)val4);
								num++;
								Log.LogInfo((object)$"Textur exportiert: {text3} ({texture.width}x{texture.height}, Material '{((Object)val3).name}', Eigenschaft {text2})");
							}
							catch (Exception ex)
							{
								Log.LogWarning((object)("Export fehlgeschlagen für " + ((Object)texture).name + ": " + ex.Message));
							}
						}
					}
				}
			}
			Log.LogInfo((object)$"{num} Textur(en) nach {text} exportiert.");
		}

		private static string Sanitize(string name)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				name = name.Replace(oldChar, '_');
			}
			if (name.Length <= 120)
			{
				return name;
			}
			return name.Substring(0, 120);
		}

		private static void DumpInfo()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("== Item-Status ==");
			stringBuilder.AppendLine("itemDictionary enthält 'Item Revive All': " + ((AccessTools.Field(typeof(StatsManager), "itemDictionary")?.GetValue(StatsManager.instance) as IDictionary)?.Contains("Item Revive All") ?? false));
			stringBuilder.AppendLine("Verbrauchte: " + UsedRevives + "  Gekaufte: " + Bonus + "  Übrig: " + RevivesLeft);
			string[] array = new string[7] { "PrefabRef", "Value", "ItemToggle", "ItemEquippable", "ItemReviveItem", "REPOLib.Modules.Items", "REPOLib.Modules.NetworkPrefabs" };
			foreach (string text in array)
			{
				DumpType(stringBuilder, AccessTools.TypeByName(text));
			}
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("== REPOLib-Typen ==");
			Type type = AccessTools.TypeByName("REPOLib.Modules.Items");
			if (type != null)
			{
				Type[] types = type.Assembly.GetTypes();
				foreach (Type type2 in types)
				{
					if (type2.IsPublic)
					{
						stringBuilder.AppendLine(type2.FullName);
					}
				}
			}
			string text2 = Path.Combine(Paths.BepInExRootPath, "ReviveAll_dump.txt");
			File.WriteAllText(text2, stringBuilder.ToString());
			Log.LogInfo((object)("Diagnose geschrieben: " + text2));
		}

		private static void DumpType(StringBuilder sb, Type t)
		{
			sb.AppendLine();
			if (t == null)
			{
				sb.AppendLine("== (Typ nicht gefunden) ==");
				return;
			}
			sb.AppendLine("== " + t.FullName + " : " + ((t.BaseType != null) ? t.BaseType.Name : "-") + " ==");
			sb.AppendLine("-- Felder --");
			FieldInfo[] fields = t.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				sb.AppendLine("  " + fieldInfo.FieldType.Name + " " + fieldInfo.Name);
			}
			sb.AppendLine("-- Methoden --");
			MethodInfo[] methods = t.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (!methodInfo.IsSpecialName)
				{
					sb.AppendLine("  " + methodInfo.ReturnType.Name + " " + methodInfo.Name + "(" + string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo p) => p.ParameterType.Name + " " + p.Name)) + ")");
				}
			}
		}

		private void SyncRevives()
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0068: Expected O, but got Unknown
			syncTimer += Time.deltaTime;
			if (syncTimer < 1f)
			{
				return;
			}
			syncTimer = 0f;
			if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient)
			{
				lastSentLeft = -1;
				return;
			}
			int revivesLeft = RevivesLeft;
			if (revivesLeft != lastSentLeft)
			{
				Hashtable val = new Hashtable();
				((Dictionary<object, object>)val).Add((object)"RA_Left", (object)revivesLeft);
				Hashtable val2 = val;
				PhotonNetwork.CurrentRoom.SetCustomProperties(val2, (Hashtable)null, (WebFlags)null);
				lastSentLeft = revivesLeft;
			}
		}

		internal static bool GetDisplay(out int left)
		{
			left = 0;
			if (!PhotonNetwork.InRoom)
			{
				if (!SemiFunc.IsMasterClientOrSingleplayer())
				{
					return false;
				}
				left = RevivesLeft;
				return true;
			}
			if (PhotonNetwork.IsMasterClient)
			{
				left = RevivesLeft;
				return true;
			}
			if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"RA_Left", out object value))
			{
				left = (int)value;
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")]
	internal static class CatalogAfterLoad
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			Plugin.TryRegister();
		}
	}
	[HarmonyPatch]
	internal static class CatalogBeforeUse
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(ItemManager), "ItemsInitialize", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(ShopManager), "GetAllItemsFromStatsManager", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(ItemManager), "GetPurchasedItems", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(StatsManager), "LoadGame", (Type[])null, (Type[])null);
		}

		private static void Prefix()
		{
			Plugin.TryRegister();
		}
	}
	[HarmonyPatch(typeof(StatsManager), "ItemPurchase")]
	internal static class ItemPurchasePatch
	{
		[HarmonyPostfix]
		private static void Postfix(StatsManager __instance, string itemName)
		{
			Plugin.Log.LogInfo((object)("ItemPurchase: " + itemName));
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			if (itemName == "Item Revive All")
			{
				Plugin.Bonus++;
				Plugin.Log.LogInfo((object)$"Wiederbelebung gekauft, übrig: {Plugin.RevivesLeft}");
			}
			else
			{
				if (!(itemName == "Item Revive Start Health"))
				{
					return;
				}
				Plugin.StartHealthBonus += 10;
				Plugin.Log.LogInfo((object)$"Revive Start Health gekauft. Zusätzlicher Revive-Startwert: +{Plugin.StartHealthBonus} HP");
			}
			if (AccessTools.Field(typeof(StatsManager), "itemsPurchased")?.GetValue(__instance) is Dictionary<string, int> dictionary && dictionary.ContainsKey(itemName))
			{
				dictionary[itemName] = 0;
			}
		}
	}
	[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
	internal static class ChangeLevelPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(RunManager __instance, bool _levelFailed, object[] __args)
		{
			if (Plugin.BypassPatch)
			{
				return true;
			}
			if (!_levelFailed)
			{
				return true;
			}
			if (Time.time < Plugin.IgnoreUntil)
			{
				return false;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return true;
			}
			if (Plugin.RevivesLeft <= 0)
			{
				Plugin.ResetCounter();
				return true;
			}
			if (Plugin.PromptOpen)
			{
				return false;
			}
			Plugin.PendingRunManager = __instance;
			Plugin.PendingArgs = __args;
			Plugin.PromptOpen = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(GoalUI), "Update")]
	internal static class GoalHudPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref TextMeshProUGUI ___Text)
		{
			if (!((Object)(object)___Text == (Object)null) && SemiFunc.RunIsLevel() && Plugin.GetDisplay(out var left))
			{
				string text = ((left == 0) ? "#ff3c3c" : "#ff9600");
				((TMP_Text)___Text).text = "<line-height=75%>" + ((TMP_Text)___Text).text + "\n<color=" + text + "><size=28>Revives " + left + "</size></color>";
				((TMP_Text)___Text).alignment = (TextAlignmentOptions)260;
			}
		}
	}
	[HarmonyPatch(typeof(EnergyUI), "Update")]
	internal static class EnergyShopHudPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ref TextMeshProUGUI ___Text)
		{
			if (!((Object)(object)___Text == (Object)null) && SemiFunc.RunIsShop() && Plugin.GetDisplay(out var left))
			{
				string text = ((left == 0) ? "#ff3c3c" : "#ff9600");
				((TMP_Text)___Text).text = "<line-height=75%>" + ((TMP_Text)___Text).text + "\n<color=" + text + "><size=28>Revives " + left + "</size></color>";
			}
		}
	}
}