Decompiled source of CostumeTracker v1.0.0

BepInEx/plugins/CostumeTracker/CostumeTracker.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: AssemblyDescription("A dedicated costume-crate detector for R.E.P.O.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyTitle("Costume Tracker")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CostumeTrackerMod;

internal static class ItemRegistration
{
	internal const string ItemId = "Item Costume Tracker";

	internal const string PrefabPath = "CostumeTracker/Item Costume Tracker";

	private static Item item;

	private static GameObject template;

	private static GameObject holder;

	internal static bool IsCostumeTracker(ItemTracker tracker)
	{
		ItemAttributes component = ((Component)tracker).GetComponent<ItemAttributes>();
		if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.item))
		{
			return ((Object)component.item).name == "Item Costume Tracker";
		}
		return false;
	}

	internal static void Register(StatsManager stats)
	{
		try
		{
			if (!Object.op_Implicit((Object)(object)item) || !Object.op_Implicit((Object)(object)template))
			{
				Create(stats);
			}
			RegisterPools(RunManager.instance);
			stats.itemDictionary["Item Costume Tracker"] = item;
			Plugin.Log.LogInfo((object)"Registered Costume Tracker as a separate shop item.");
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Costume Tracker registration failed: " + ex));
		}
	}

	private static void Create(StatsManager stats)
	{
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Expected O, but got Unknown
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Expected O, but got Unknown
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		Item val = null;
		foreach (Item value3 in stats.itemDictionary.Values)
		{
			if (string.Equals(value3.itemName, "Valuable Tracker", StringComparison.OrdinalIgnoreCase) || (((Object)value3).name.IndexOf("tracker", StringComparison.OrdinalIgnoreCase) >= 0 && ((Object)value3).name.IndexOf("valuable", StringComparison.OrdinalIgnoreCase) >= 0))
			{
				val = value3;
				break;
			}
		}
		if (!Object.op_Implicit((Object)(object)val))
		{
			throw new InvalidOperationException("The vanilla Valuable Tracker item was not found.");
		}
		GameObject prefab = ((PrefabRef<GameObject>)(object)val.prefab).Prefab;
		if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<ItemTracker>()))
		{
			throw new InvalidOperationException("The vanilla Valuable Tracker prefab is unavailable.");
		}
		holder = new GameObject("Costume Tracker Prefab Storage");
		holder.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)holder);
		template = Object.Instantiate<GameObject>(prefab, holder.transform, false);
		((Object)template).name = "Item Costume Tracker";
		item = Object.Instantiate<Item>(val);
		((Object)item).name = "Item Costume Tracker";
		item.itemName = "Costume Tracker";
		item.itemNameLocalized = null;
		item.description = TrackerLocalization.Get("description");
		item.value = Object.Instantiate<Value>(val.value);
		((Object)item.value).name = "Costume Tracker Value";
		Value value = item.value;
		value.valueMin += 2500f;
		Value value2 = item.value;
		value2.valueMax += 2500f;
		item.status = (Status)1;
		item.disabled = false;
		item.prefab = new PrefabRef();
		((PrefabRef<GameObject>)(object)item.prefab).SetPrefab(template, "CostumeTracker/Item Costume Tracker");
		template.GetComponent<ItemAttributes>().item = item;
		template.GetComponent<ItemTracker>().trackerType = (TrackerType)0;
		TrackerSkin.Apply(template);
		template.SetActive(true);
		Object.DontDestroyOnLoad((Object)(object)item);
	}

	internal static void RegisterPools(RunManager run)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Expected O, but got Unknown
		if (Object.op_Implicit((Object)(object)run) && Object.op_Implicit((Object)(object)template))
		{
			Dictionary<string, Object> dictionary = (Dictionary<string, Object>)AccessTools.Field(typeof(RunManager), "singleplayerPool").GetValue(run);
			MultiplayerPool val = (MultiplayerPool)AccessTools.Field(typeof(RunManager), "multiplayerPool").GetValue(run);
			dictionary["CostumeTracker/Item Costume Tracker"] = (Object)(object)template;
			val.ResourceCache["CostumeTracker/Item Costume Tracker"] = template;
		}
	}
}
[HarmonyPatch(typeof(StatsManager), "LoadItemsFromFolder")]
internal static class RegisterItemPatch
{
	private static void Postfix(StatsManager __instance)
	{
		ItemRegistration.Register(__instance);
	}
}
[HarmonyPatch(typeof(RunManager), "Awake")]
internal static class RegisterPoolsPatch
{
	private static void Postfix(RunManager __instance)
	{
		ItemRegistration.RegisterPools(__instance);
	}
}
[HarmonyPatch(typeof(LevelGenerator), "Start")]
internal static class RestorePoolsAfterSceneStartPatch
{
	private static void Postfix()
	{
		ItemRegistration.RegisterPools(RunManager.instance);
	}
}
[HarmonyPatch(typeof(LevelGenerator), "PrefabsLoad")]
internal static class RestorePoolsBeforePrefabLoadPatch
{
	private static void Prefix()
	{
		ItemRegistration.RegisterPools(RunManager.instance);
	}
}
[BepInPlugin("local.repo.costumetracker", "Costume Tracker", "1.0.0")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string Id = "local.repo.costumetracker";

	public const string Version = "1.0.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<float> ScanRange;

	internal static ConfigEntry<bool> TrackDiscovered;

	private void Awake()
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		ScanRange = ((BaseUnityPlugin)this).Config.Bind<float>("Tracking", "ScanRange", 30f, new ConfigDescription("Maximum distance in metres to a costume crate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 500f), new object[0]));
		TrackDiscovered = ((BaseUnityPlugin)this).Config.Bind<bool>("Tracking", "TrackDiscovered", false, "Also track crates already discovered by the team. Grabbed crates and crates in carts or extraction points are excluded.");
		TrackerLocalization.Initialize(((BaseUnityPlugin)this).Config.Bind<string>("Localization", "Language", "auto", "auto follows the game language. You may override it with a locale such as en, ja, ko, zh-Hans, zh-Hant, fr or de. Unsupported locales use English."));
		try
		{
			new Harmony("local.repo.costumetracker").PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Costume Tracker 1.0.0 loaded.");
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not install Costume Tracker patches: " + ex));
			throw;
		}
	}
}
[HarmonyPatch(typeof(ItemBattery), "DrainContinuous")]
internal static class TrackerBatteryPatch
{
	private static void Prefix(ItemBattery __instance, ref float _rate)
	{
		ItemAttributes component = ((Component)__instance).GetComponent<ItemAttributes>();
		if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.item) && ((Object)component.item).name == "Item Costume Tracker")
		{
			_rate *= 0.8f;
		}
	}
}
internal static class TrackerColors
{
	internal static readonly Color Neutral = new Color(0.65f, 0.65f, 0.65f, 1f);

	internal static Color ForTarget(Transform target)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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_004b: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)target) || !Object.op_Implicit((Object)(object)((Component)target).GetComponent<CosmeticWorldObject>()))
		{
			return Neutral;
		}
		ValuableDiscoverCustom component = ((Component)target).GetComponent<ValuableDiscoverCustom>();
		if (Object.op_Implicit((Object)(object)component))
		{
			Color colorCorner = component.colorCorner;
			colorCorner.a = 1f;
			if (((Color)(ref colorCorner)).maxColorComponent > 0.05f)
			{
				return colorCorner;
			}
		}
		return Neutral;
	}

	internal static void Apply(ItemTracker tracker, Color color)
	{
		//IL_0013: 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_003f: 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_0058: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)tracker.displayText))
		{
			((Graphic)tracker.displayText).color = color;
		}
		if (Object.op_Implicit((Object)(object)tracker.displayLight))
		{
			tracker.displayLight.color = color;
		}
		if (Object.op_Implicit((Object)(object)tracker.display))
		{
			Color color2 = color;
			color2.a = 0.2f;
			((Renderer)tracker.display).material.color = color2;
		}
	}
}
[HarmonyPatch(typeof(ItemTracker), "Start")]
internal static class InitializeTrackerColorsPatch
{
	private static void Postfix(ItemTracker __instance)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		if (ItemRegistration.IsCostumeTracker(__instance))
		{
			__instance.colorScreenNeutral = TrackerColors.Neutral;
			__instance.colorTargetFound = TrackerColors.Neutral;
			TrackerColors.Apply(__instance, TrackerColors.Neutral);
			if (Object.op_Implicit((Object)(object)__instance.displayText))
			{
				float fontSize = ((TMP_Text)__instance.displayText).fontSize;
				((TMP_Text)__instance.displayText).fontSizeMax = fontSize;
				((TMP_Text)__instance.displayText).fontSizeMin = fontSize * 0.3f;
				((TMP_Text)__instance.displayText).enableAutoSizing = true;
			}
			TrackerFlowGlow.Attach(__instance);
		}
	}
}
[HarmonyPatch(typeof(ItemTracker), "Update")]
internal static class UpdateTrackerColorsPatch
{
	private static void Postfix(ItemTracker __instance, ItemToggle ___itemToggle, bool ___hasTarget, Transform ___currentTarget, float ___displayOverrideTimer)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		if (!ItemRegistration.IsCostumeTracker(__instance))
		{
			return;
		}
		bool flag = ___itemToggle.toggleState && ___hasTarget && Object.op_Implicit((Object)(object)___currentTarget) && ___displayOverrideTimer <= 0f;
		Color val = (flag ? TrackerColors.ForTarget(___currentTarget) : TrackerColors.Neutral);
		TrackerFlowGlow component = ((Component)__instance).GetComponent<TrackerFlowGlow>();
		if (Object.op_Implicit((Object)(object)component))
		{
			bool flag2 = ___itemToggle.toggleState && ___displayOverrideTimer > 0f && Object.op_Implicit((Object)(object)__instance.displayText) && ((TMP_Text)__instance.displayText).text == TrackerLocalization.Get("found");
			component.SetState(flag ? ___currentTarget : null, flag2 ? __instance.colorTargetFound : val, flag2);
		}
		if (!(___displayOverrideTimer > 0f))
		{
			__instance.colorScreenNeutral = TrackerColors.Neutral;
			if (flag)
			{
				__instance.colorTargetFound = val;
			}
			TrackerColors.Apply(__instance, val);
		}
	}
}
[HarmonyPatch(typeof(ItemTracker), "CurrentTargetUpdateRPC")]
internal static class FoundTrackerColorPatch
{
	private static void Prefix(ItemTracker __instance, Transform ___currentTarget)
	{
		//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)
		if (ItemRegistration.IsCostumeTracker(__instance) && Object.op_Implicit((Object)(object)___currentTarget))
		{
			__instance.colorTargetFound = TrackerColors.ForTarget(___currentTarget);
		}
	}
}
public sealed class TrackerFlowGlow : MonoBehaviour
{
	private const int FrameCount = 32;

	private const float CycleSeconds = 1.8f;

	private static Texture2D[] frames;

	private ItemTracker tracker;

	private Material body;

	private Texture originalEmission;

	private Transform target;

	private Color targetColor;

	private float startedAt;

	private bool found;

	private int previousFrame = -2;

	internal static void Attach(ItemTracker tracker)
	{
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			TrackerFlowGlow component = ((Component)tracker).GetComponent<TrackerFlowGlow>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				if (frames == null)
				{
					frames = LoadFrames();
				}
				component = ((Component)tracker).gameObject.AddComponent<TrackerFlowGlow>();
				component.tracker = tracker;
				component.body = ((Renderer)tracker.meshRenderer).material;
				if (!component.body.HasProperty("_EmissionTexture"))
				{
					throw new InvalidOperationException("Tracker body shader has no emission texture slot.");
				}
				component.originalEmission = component.body.GetTexture("_EmissionTexture");
				if (component.body.HasProperty("_FresnelEmissionColor"))
				{
					component.body.SetColor("_FresnelEmissionColor", Color.black);
				}
				if (component.body.HasProperty("_FresnelColor"))
				{
					Color neutral = TrackerColors.Neutral;
					neutral.a = component.body.GetColor("_FresnelColor").a;
					component.body.SetColor("_FresnelColor", neutral);
				}
				Plugin.Log.LogInfo((object)"Cable-to-ring emission flow ready.");
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Could not initialize cable-to-ring emission: " + ex));
			TrackerFlowGlow component2 = ((Component)tracker).GetComponent<TrackerFlowGlow>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				((Behaviour)component2).enabled = false;
			}
		}
	}

	internal void SetState(Transform newTarget, Color color, bool targetFound)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)newTarget) && (Object)(object)newTarget != (Object)(object)target)
		{
			startedAt = Time.time;
		}
		target = newTarget;
		targetColor = color;
		found = targetFound;
	}

	private void LateUpdate()
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)tracker) || !Object.op_Implicit((Object)(object)body))
		{
			return;
		}
		if (!Object.op_Implicit((Object)(object)target) && !found)
		{
			if (previousFrame != -1)
			{
				body.SetTexture("_EmissionTexture", originalEmission);
			}
			previousFrame = -1;
			body.SetColor("_EmissionColor", Color.black);
			if (Object.op_Implicit((Object)(object)tracker.nozzleLight))
			{
				((Behaviour)tracker.nozzleLight).enabled = false;
				tracker.nozzleLight.intensity = 0f;
			}
			return;
		}
		float num = (found ? 0.8f : Mathf.Repeat((Time.time - startedAt) / 1.8f, 1f));
		int num2 = Mathf.Min(31, Mathf.FloorToInt(num * 32f));
		if (num2 != previousFrame)
		{
			body.SetTexture("_EmissionTexture", (Texture)(object)frames[num2]);
			previousFrame = num2;
		}
		body.SetColor("_EmissionColor", targetColor * 3f);
		if (Object.op_Implicit((Object)(object)tracker.nozzleLight))
		{
			float num3 = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.6f, 0.74f, num)) * (1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.86f, 1f, num)));
			tracker.nozzleLight.color = targetColor;
			tracker.nozzleLight.intensity = num3 * 0.9f;
			((Behaviour)tracker.nozzleLight).enabled = num3 > 0.01f;
		}
	}

	private static Texture2D[] LoadFrames()
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Expected O, but got Unknown
		Texture2D[] array = (Texture2D[])(object)new Texture2D[32];
		try
		{
			for (int i = 0; i < array.Length; i++)
			{
				string text = "CostumeTracker.Flow." + i.ToString("D2") + ".png";
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text);
				if (stream == null)
				{
					throw new FileNotFoundException("Missing emissive data frame: " + text);
				}
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				array[i] = new Texture2D(2, 2, (TextureFormat)4, false, true);
				((Object)array[i]).name = "Costume Tracker Cable Flow " + i;
				((Texture)array[i]).filterMode = (FilterMode)1;
				((Texture)array[i]).wrapMode = (TextureWrapMode)0;
				if (!ImageConversion.LoadImage(array[i], memoryStream.ToArray(), true))
				{
					throw new InvalidDataException("Cannot decode emissive data frame: " + text);
				}
			}
			return array;
		}
		catch
		{
			Texture2D[] array2 = array;
			foreach (Texture2D val in array2)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					Object.Destroy((Object)(object)val);
				}
			}
			throw;
		}
	}
}
internal static class TrackerLocalization
{
	[Serializable]
	public sealed class Translation
	{
		public string locale;

		public string name;

		public string description;

		public string found;

		public string lost;
	}

	[Serializable]
	public sealed class Catalog
	{
		public Translation[] translations = new Translation[0];
	}

	private static readonly Dictionary<string, Translation> translations = new Dictionary<string, Translation>(StringComparer.OrdinalIgnoreCase);

	private static readonly Translation English = new Translation
	{
		locale = "en",
		name = "Costume Tracker",
		description = "Tracks nearby costume crates. The display and flowing lights match the target's color.",
		found = "FOUND",
		lost = "NO TARGET"
	};

	private static ConfigEntry<string> language;

	internal static void Initialize(ConfigEntry<string> setting)
	{
		language = setting;
		translations["en"] = English;
		try
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("CostumeTracker.Localization.json");
			using StreamReader streamReader = new StreamReader(stream);
			Catalog catalog = JsonUtility.FromJson<Catalog>(streamReader.ReadToEnd());
			Translation[] array = catalog.translations;
			foreach (Translation translation in array)
			{
				translations[translation.locale] = translation;
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Cannot load translations; using English: " + ex));
		}
	}

	internal static string ResolveLocale(string code)
	{
		code = (code ?? "en").Replace('_', '-').ToLowerInvariant();
		if (translations.ContainsKey(code))
		{
			return code;
		}
		if (code.StartsWith("zh"))
		{
			if (!code.Contains("hant") && !code.Contains("tw") && !code.Contains("hk") && !code.Contains("mo"))
			{
				return "zh-hans";
			}
			return "zh-hant";
		}
		if (code == "nb" || code.StartsWith("nb-") || code == "nn" || code.StartsWith("nn-"))
		{
			return "no";
		}
		int num = code.IndexOf('-');
		if (num >= 0)
		{
			code = code.Substring(0, num);
		}
		if (!translations.ContainsKey(code))
		{
			return "en";
		}
		return code;
	}

	internal static string Get(string key)
	{
		string text = ((language == null) ? "auto" : language.Value);
		if (string.IsNullOrWhiteSpace(text) || string.Equals(text, "auto", StringComparison.OrdinalIgnoreCase))
		{
			text = SemiFunc.LocaleGetCode();
		}
		if (!translations.TryGetValue(ResolveLocale(text), out var value))
		{
			value = English;
		}
		return key switch
		{
			"name" => value.name, 
			"description" => value.description, 
			"found" => value.found, 
			"lost" => value.lost, 
			_ => key, 
		};
	}

	internal static void EnsureScreenFont(TextMeshPro text, string message)
	{
		uint[] array = default(uint[]);
		if (!Object.op_Implicit((Object)(object)text) || !Object.op_Implicit((Object)(object)((TMP_Text)text).font) || ((TMP_Text)text).font.HasCharacters(message, ref array, true, true))
		{
			return;
		}
		TMP_FontAsset[] array2 = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
		foreach (TMP_FontAsset val in array2)
		{
			if (Object.op_Implicit((Object)(object)val) && val.HasCharacters(message, ref array, true, true))
			{
				((TMP_Text)text).font = val;
				break;
			}
		}
	}

	internal static void RefreshScreen(ItemTracker tracker)
	{
		if (!Object.op_Implicit((Object)(object)tracker.displayText))
		{
			return;
		}
		string text = ((TMP_Text)tracker.displayText).text;
		foreach (Translation value in translations.Values)
		{
			string text2 = ((text == value.found) ? "found" : ((text == value.lost) ? "lost" : null));
			if (text2 != null)
			{
				string text3 = Get(text2);
				EnsureScreenFont(tracker.displayText, text3);
				((TMP_Text)tracker.displayText).text = text3;
				break;
			}
		}
	}
}
[HarmonyPatch(typeof(ItemAttributes), "RefreshLocalizations")]
internal static class LocalizeTrackerNamePatch
{
	private static void Postfix(ItemAttributes __instance, ref string ___cachedItemName, ref string ___promptName, ref string ___itemTag)
	{
		if (Object.op_Implicit((Object)(object)__instance.item) && !(((Object)__instance.item).name != "Item Costume Tracker"))
		{
			___cachedItemName = TrackerLocalization.Get("name");
			__instance.item.description = TrackerLocalization.Get("description");
			___promptName = "";
			___itemTag = "";
		}
	}
}
[HarmonyPatch(typeof(ItemTracker), "DisplayColorOverride")]
internal static class LocalizeTrackerStatusPatch
{
	private static void Prefix(ItemTracker __instance, ref string _text)
	{
		if (ItemRegistration.IsCostumeTracker(__instance))
		{
			if (_text == "FOUND")
			{
				_text = TrackerLocalization.Get("found");
			}
			else if (_text == "NOT FOUND")
			{
				_text = TrackerLocalization.Get("lost");
			}
			TrackerLocalization.EnsureScreenFont(__instance.displayText, _text);
		}
	}
}
[HarmonyPatch(typeof(LocalizationManager), "NotifyLocalizationChanged")]
internal static class RefreshTrackerLanguagePatch
{
	private static void Postfix()
	{
		ItemTracker[] array = Object.FindObjectsByType<ItemTracker>((FindObjectsSortMode)0);
		foreach (ItemTracker tracker in array)
		{
			if (ItemRegistration.IsCostumeTracker(tracker))
			{
				TrackerLocalization.RefreshScreen(tracker);
			}
		}
	}
}
internal static class CostumeTargets
{
	private static readonly FieldInfo Discovered = AccessTools.Field(typeof(ValuableDiscoverCustom), "discovered");

	private static readonly FieldInfo InCart = AccessTools.Field(typeof(PhysGrabObjectImpactDetector), "inCart");

	private static readonly FieldInfo InExtraction = AccessTools.Field(typeof(CosmeticWorldObject), "inExtraction");

	internal static readonly MethodInfo SetTarget = AccessTools.Method(typeof(ItemTracker), "SetTarget", (Type[])null, (Type[])null);

	internal static readonly MethodInfo UpdateTarget = AccessTools.Method(typeof(ItemTracker), "CurrentTargetUpdate", (Type[])null, (Type[])null);

	internal static bool IsDiscovered(ValuableDiscoverCustom discover)
	{
		if (Object.op_Implicit((Object)(object)discover))
		{
			return (bool)Discovered.GetValue(discover);
		}
		return false;
	}

	internal static bool IsEligible(CosmeticWorldObject costume, PhysGrabObject physical, ValuableDiscoverCustom discover)
	{
		if (!Object.op_Implicit((Object)(object)costume) || !((Component)costume).gameObject.activeInHierarchy || !Object.op_Implicit((Object)(object)physical) || physical.grabbed)
		{
			return false;
		}
		if (!Plugin.TrackDiscovered.Value && IsDiscovered(discover))
		{
			return false;
		}
		PhysGrabObjectImpactDetector component = ((Component)physical).GetComponent<PhysGrabObjectImpactDetector>();
		if (!Object.op_Implicit((Object)(object)component) || !(bool)InCart.GetValue(component))
		{
			return !(bool)InExtraction.GetValue(costume);
		}
		return false;
	}
}
[HarmonyPatch(typeof(ItemTracker), "ValuableTarget")]
internal static class FindCostumePatch
{
	private static bool Prefix(ItemTracker __instance, ref bool ___hasTarget, ref Transform ___currentTarget, ref PhysGrabObject ___currentTargetPhysGrabObject, ref ValuableObject ___currentTargetValuable, ref ValuableDiscoverCustom ___currentTargetValuableCustom)
	{
		//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_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		if (!ItemRegistration.IsCostumeTracker(__instance))
		{
			return true;
		}
		PhysGrabObject val = null;
		ValuableDiscoverCustom val2 = null;
		float num = float.MaxValue;
		float num2 = Plugin.ScanRange.Value * Plugin.ScanRange.Value;
		Vector3 position = __instance.nozzleTransform.position;
		Collider[] array = Physics.OverlapSphere(position, Plugin.ScanRange.Value, LayerMask.op_Implicit(SemiFunc.LayerMaskGetPhysGrabObject()), (QueryTriggerInteraction)1);
		Collider[] array2 = array;
		foreach (Collider val3 in array2)
		{
			CosmeticWorldObject componentInParent = ((Component)val3).GetComponentInParent<CosmeticWorldObject>();
			if (!Object.op_Implicit((Object)(object)componentInParent))
			{
				continue;
			}
			PhysGrabObject component = ((Component)componentInParent).GetComponent<PhysGrabObject>();
			ValuableDiscoverCustom component2 = ((Component)componentInParent).GetComponent<ValuableDiscoverCustom>();
			if (CostumeTargets.IsEligible(componentInParent, component, component2))
			{
				Vector3 val4 = component.midPoint - position;
				float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
				if (!(sqrMagnitude > num2) && !(sqrMagnitude >= num))
				{
					val = component;
					val2 = component2;
					num = sqrMagnitude;
				}
			}
		}
		if (!Object.op_Implicit((Object)(object)val))
		{
			if (___hasTarget)
			{
				CostumeTargets.UpdateTarget.Invoke(__instance, new object[1] { false });
			}
			___hasTarget = false;
			___currentTarget = null;
			___currentTargetPhysGrabObject = null;
			___currentTargetValuable = null;
			___currentTargetValuableCustom = null;
			return false;
		}
		___currentTarget = ((Component)val).transform;
		___currentTargetPhysGrabObject = val;
		___currentTargetValuable = null;
		___currentTargetValuableCustom = val2;
		___hasTarget = true;
		PhotonView component3 = ((Component)val).GetComponent<PhotonView>();
		if (Object.op_Implicit((Object)(object)component3) && component3.ViewID != 0)
		{
			CostumeTargets.SetTarget.Invoke(__instance, new object[1] { component3.ViewID });
		}
		return false;
	}
}
[HarmonyPatch(typeof(ItemTracker), "TargetLogic")]
internal static class ValidateCostumePatch
{
	private static bool Prefix(ItemTracker __instance, ItemToggle ___itemToggle, ref bool ___hasTarget, ref Transform ___currentTarget, ref PhysGrabObject ___currentTargetPhysGrabObject, ref ValuableObject ___currentTargetValuable, ref ValuableDiscoverCustom ___currentTargetValuableCustom, ref float ___displayOverrideTimer)
	{
		//IL_0076: 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_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		if (!ItemRegistration.IsCostumeTracker(__instance))
		{
			return true;
		}
		if (!SemiFunc.IsMasterClientOrSingleplayer())
		{
			return false;
		}
		if (!___itemToggle.toggleState)
		{
			___hasTarget = false;
			___currentTarget = null;
			___currentTargetPhysGrabObject = null;
			___currentTargetValuable = null;
			___currentTargetValuableCustom = null;
			___displayOverrideTimer = 0f;
			return false;
		}
		if (!___hasTarget)
		{
			return false;
		}
		CosmeticWorldObject costume = (Object.op_Implicit((Object)(object)___currentTarget) ? ((Component)___currentTarget).GetComponent<CosmeticWorldObject>() : null);
		bool flag = !Plugin.TrackDiscovered.Value && CostumeTargets.IsDiscovered(___currentTargetValuableCustom);
		int num;
		if (Object.op_Implicit((Object)(object)___currentTargetPhysGrabObject))
		{
			Vector3 val = ___currentTargetPhysGrabObject.midPoint - __instance.nozzleTransform.position;
			num = ((((Vector3)(ref val)).sqrMagnitude <= Plugin.ScanRange.Value * Plugin.ScanRange.Value) ? 1 : 0);
		}
		else
		{
			num = 0;
		}
		bool flag2 = (byte)num != 0;
		if (flag || !flag2 || !CostumeTargets.IsEligible(costume, ___currentTargetPhysGrabObject, ___currentTargetValuableCustom))
		{
			CostumeTargets.UpdateTarget.Invoke(__instance, new object[1] { flag });
			___currentTargetValuable = null;
			___currentTargetValuableCustom = null;
		}
		return false;
	}
}
internal static class TrackerSkin
{
	private const string ResourceName = "CostumeTracker.ElectronicGray.png";

	private static readonly string[] BaseTextureProperties = new string[3] { "_BaseTexture", "_BaseMap", "_MainTex" };

	private static Texture2D surface;

	internal static void Apply(GameObject prefab)
	{
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Expected O, but got Unknown
		try
		{
			if (!Object.op_Implicit((Object)(object)surface))
			{
				surface = LoadSurface();
			}
			Dictionary<Material, Material> dictionary = new Dictionary<Material, Material>();
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val2 = sharedMaterials[j];
					if (!Object.op_Implicit((Object)(object)val2))
					{
						continue;
					}
					if (!dictionary.TryGetValue(val2, out var value))
					{
						string[] baseTextureProperties = BaseTextureProperties;
						foreach (string text in baseTextureProperties)
						{
							if (!val2.HasProperty(text))
							{
								continue;
							}
							Texture texture = val2.GetTexture(text);
							if (Object.op_Implicit((Object)(object)texture) && string.Equals(((Object)texture).name, "valuable tracker_DefaultMaterial_BaseColor", StringComparison.OrdinalIgnoreCase))
							{
								if (!Object.op_Implicit((Object)(object)value))
								{
									value = new Material(val2);
									((Object)value).name = "Costume Tracker - Electronic Gray";
									dictionary.Add(val2, value);
								}
								value.SetTexture(text, (Texture)(object)surface);
							}
						}
					}
					if (Object.op_Implicit((Object)(object)value))
					{
						sharedMaterials[j] = value;
						flag = true;
					}
				}
				if (flag)
				{
					val.sharedMaterials = sharedMaterials;
				}
			}
			if (dictionary.Count == 0)
			{
				Plugin.Log.LogWarning((object)"Electronic Gray skin: no matching body material was found.");
			}
			else
			{
				Plugin.Log.LogInfo((object)("Electronic Gray skin applied to " + dictionary.Count + " body material(s)."));
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Could not apply Electronic Gray skin: " + ex));
		}
	}

	private static Texture2D LoadSurface()
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("CostumeTracker.ElectronicGray.png");
		if (stream == null)
		{
			throw new FileNotFoundException("Missing embedded skin: CostumeTracker.ElectronicGray.png");
		}
		using MemoryStream memoryStream = new MemoryStream();
		stream.CopyTo(memoryStream);
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, false);
		((Object)val).name = "Costume Tracker Electronic Gray Albedo";
		((Texture)val).filterMode = (FilterMode)1;
		((Texture)val).wrapMode = (TextureWrapMode)0;
		if (!ImageConversion.LoadImage(val, memoryStream.ToArray(), true))
		{
			Object.Destroy((Object)(object)val);
			throw new InvalidDataException("Electronic Gray PNG could not be decoded.");
		}
		return val;
	}
}