Decompiled source of ScanValue v0.0.1

BepInEx/plugins/ScanValue/ScanValue.Core.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ScanValue.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+dc2e2945334d0124669ecf1cd91a828da6fa9e8b")]
[assembly: AssemblyProduct("ScanValue.Core")]
[assembly: AssemblyTitle("ScanValue.Core")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Auuueser.ScanValue.Core.Localization
{
	public static class ScrapNameDictionaryFiles
	{
		public static bool IsActiveDictionaryFile(string? path)
		{
			if (string.IsNullOrWhiteSpace(path))
			{
				return false;
			}
			string fileName = Path.GetFileName(path);
			if (fileName.EndsWith(".old", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (!string.Equals(fileName, "zh-CN.runtime.json", StringComparison.OrdinalIgnoreCase))
			{
				return string.Equals(Path.GetExtension(fileName), ".cfg", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}
	}
	public static class ScrapNameDictionaryParser
	{
		public static ScrapNameTranslationMap ParseCfg(string text)
		{
			ScrapNameTranslationMap scrapNameTranslationMap = new ScrapNameTranslationMap();
			AddCfg(scrapNameTranslationMap, text);
			return scrapNameTranslationMap;
		}

		public static void AddCfg(ScrapNameTranslationMap map, string? text)
		{
			if (map == null)
			{
				throw new ArgumentNullException("map");
			}
			if (!string.IsNullOrEmpty(text))
			{
				string[] array = text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.None);
				for (int i = 0; i < array.Length; i++)
				{
					AddCfgLine(map, array[i]);
				}
			}
		}

		public static ScrapNameTranslationMap ParseRuntimeJson(string text)
		{
			ScrapNameTranslationMap scrapNameTranslationMap = new ScrapNameTranslationMap();
			AddRuntimeJson(scrapNameTranslationMap, text);
			return scrapNameTranslationMap;
		}

		public static void AddRuntimeJson(ScrapNameTranslationMap map, string? text)
		{
			if (map == null)
			{
				throw new ArgumentNullException("map");
			}
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			foreach (string item in EnumerateJsonObjects(text))
			{
				if (!TryGetJsonStringProperty(item, "source", out string value))
				{
					continue;
				}
				TryGetJsonStringProperty(item, "target", out string value2);
				TryGetJsonStringProperty(item, "mode", out string value3);
				if (!string.Equals(value3, "skip", StringComparison.OrdinalIgnoreCase) && !string.Equals(value3, "regex-preserve", StringComparison.OrdinalIgnoreCase))
				{
					string text2 = (string.Equals(value3, "preserve", StringComparison.OrdinalIgnoreCase) ? value : value2);
					if (!string.IsNullOrWhiteSpace(text2))
					{
						map.Add(value, text2);
					}
				}
			}
		}

		private static void AddCfgLine(ScrapNameTranslationMap map, string rawLine)
		{
			string text = rawLine.Trim();
			if (text.Length != 0 && !text.StartsWith("#", StringComparison.Ordinal) && !text.StartsWith("//", StringComparison.Ordinal) && !text.StartsWith("/*", StringComparison.Ordinal) && !IsRegexCfgLine(text))
			{
				int num = FindCfgEntrySeparator(text);
				if (num > 0)
				{
					string source = UnescapeCfgValue(text.Substring(0, num).Trim());
					string target = UnescapeCfgValue(text.Substring(num + 1).Trim());
					map.Add(source, target);
				}
			}
		}

		private static bool IsRegexCfgLine(string line)
		{
			if (!line.StartsWith("r:\"", StringComparison.Ordinal) && !line.StartsWith("sr:\"", StringComparison.Ordinal))
			{
				return line.StartsWith("rex:", StringComparison.Ordinal);
			}
			return true;
		}

		private static int FindCfgEntrySeparator(string line)
		{
			bool flag = false;
			bool flag2 = false;
			for (int i = 0; i < line.Length; i++)
			{
				char c = line[i];
				if (flag)
				{
					flag = false;
					continue;
				}
				switch (c)
				{
				case '\\':
					flag = true;
					continue;
				case '<':
					flag2 = true;
					continue;
				}
				if (flag2)
				{
					if (c == '>')
					{
						flag2 = false;
					}
				}
				else if (c == '=')
				{
					return i;
				}
			}
			return -1;
		}

		private static string UnescapeCfgValue(string value)
		{
			return value.Replace("\\n", "\n", StringComparison.Ordinal).Replace("\\r", "\r", StringComparison.Ordinal).Replace("\\t", "\t", StringComparison.Ordinal)
				.Replace("\\=", "=", StringComparison.Ordinal)
				.Replace("\\\"", "\"", StringComparison.Ordinal);
		}

		private static IEnumerable<string> EnumerateJsonObjects(string text)
		{
			int depth = 0;
			List<int> starts = new List<int>();
			bool inString = false;
			bool escaped = false;
			for (int index = 0; index < text.Length; index++)
			{
				char c = text[index];
				if (inString)
				{
					if (escaped)
					{
						escaped = false;
						continue;
					}
					switch (c)
					{
					case '\\':
						escaped = true;
						break;
					case '"':
						inString = false;
						break;
					}
					continue;
				}
				switch (c)
				{
				case '"':
					inString = true;
					break;
				case '{':
					starts.Add(index);
					depth++;
					break;
				case '}':
					if (depth != 0)
					{
						int num = starts[starts.Count - 1];
						starts.RemoveAt(starts.Count - 1);
						depth--;
						if (depth >= 1)
						{
							yield return text.Substring(num, index - num + 1);
						}
					}
					break;
				}
			}
		}

		private static bool TryGetJsonStringProperty(string jsonObject, string propertyName, out string value)
		{
			value = string.Empty;
			string text = "\"" + propertyName + "\"";
			int num = jsonObject.IndexOf(text, StringComparison.Ordinal);
			if (num < 0)
			{
				return false;
			}
			for (num += text.Length; num < jsonObject.Length && char.IsWhiteSpace(jsonObject[num]); num++)
			{
			}
			if (num >= jsonObject.Length || jsonObject[num] != ':')
			{
				return false;
			}
			for (num++; num < jsonObject.Length && char.IsWhiteSpace(jsonObject[num]); num++)
			{
			}
			if (num >= jsonObject.Length || jsonObject[num] != '"')
			{
				return false;
			}
			num++;
			List<char> list = new List<char>();
			bool flag = false;
			for (; num < jsonObject.Length; num++)
			{
				char c = jsonObject[num];
				if (flag)
				{
					if (c == 'u' && num + 4 < jsonObject.Length && ushort.TryParse(jsonObject.Substring(num + 1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
					{
						list.Add((char)result);
						num += 4;
					}
					else
					{
						List<char> list2 = list;
						list2.Add(c switch
						{
							'n' => '\n', 
							'r' => '\r', 
							't' => '\t', 
							'"' => '"', 
							'\\' => '\\', 
							'/' => '/', 
							_ => c, 
						});
					}
					flag = false;
				}
				else
				{
					switch (c)
					{
					case '\\':
						flag = true;
						break;
					case '"':
						value = new string(list.ToArray());
						return true;
					default:
						list.Add(c);
						break;
					}
				}
			}
			return false;
		}
	}
	public sealed class ScrapNameTranslationMap
	{
		private readonly Dictionary<string, string> englishToChinese = new Dictionary<string, string>(256, StringComparer.Ordinal);

		private readonly Dictionary<string, string> chineseToEnglish = new Dictionary<string, string>(256, StringComparer.Ordinal);

		public int Count => englishToChinese.Count;

		public bool HasEntries => englishToChinese.Count > 0;

		public void Add(string? source, string? target)
		{
			if (string.IsNullOrWhiteSpace(source) || string.IsNullOrWhiteSpace(target))
			{
				return;
			}
			string text = source.Trim();
			string text2 = target.Trim();
			if (text.Length != 0 && text2.Length != 0)
			{
				if (!englishToChinese.ContainsKey(text))
				{
					englishToChinese.Add(text, text2);
				}
				if (!chineseToEnglish.ContainsKey(text2))
				{
					chineseToEnglish.Add(text2, text);
				}
			}
		}

		public string ToChinese(string currentName)
		{
			if (!englishToChinese.TryGetValue(currentName, out string value))
			{
				return currentName;
			}
			return value;
		}

		public string ToEnglish(string currentName)
		{
			if (!chineseToEnglish.TryGetValue(currentName, out string value))
			{
				return currentName;
			}
			return value;
		}
	}
}
namespace Auuueser.ScanValue.Core.Domain
{
	public sealed class ScrapDebugOptions
	{
		private const float MinLogIntervalSeconds = 0.25f;

		private const float MaxLogIntervalSeconds = 30f;

		public static ScrapDebugOptions Disabled { get; } = Create(enabled: false, diagnosticsEnabled: false, showHeldItems: false, showZeroValueItems: false, logRegistrations: false, showCameraTestLabel: false, 3f);

		public bool Enabled { get; }

		public bool DiagnosticsEnabled { get; }

		public bool ShowHeldItems { get; }

		public bool ShowZeroValueItems { get; }

		public bool LogRegistrations { get; }

		public bool ShowCameraTestLabel { get; }

		public float LogIntervalSeconds { get; }

		public bool ShouldLogDiagnostics
		{
			get
			{
				if (Enabled)
				{
					return DiagnosticsEnabled;
				}
				return false;
			}
		}

		public bool ShouldLogRegistrations
		{
			get
			{
				if (Enabled)
				{
					return LogRegistrations;
				}
				return false;
			}
		}

		public bool ShouldShowCameraTestLabel
		{
			get
			{
				if (Enabled)
				{
					return ShowCameraTestLabel;
				}
				return false;
			}
		}

		public bool LogVisibilitySummary => DiagnosticsEnabled;

		private ScrapDebugOptions(bool enabled, bool diagnosticsEnabled, bool showHeldItems, bool showZeroValueItems, bool logRegistrations, bool showCameraTestLabel, float logIntervalSeconds)
		{
			Enabled = enabled;
			DiagnosticsEnabled = diagnosticsEnabled;
			ShowHeldItems = showHeldItems;
			ShowZeroValueItems = showZeroValueItems;
			LogRegistrations = logRegistrations;
			ShowCameraTestLabel = showCameraTestLabel;
			LogIntervalSeconds = logIntervalSeconds;
		}

		public static ScrapDebugOptions Create(bool enabled, bool diagnosticsEnabled, bool showHeldItems, bool showZeroValueItems, bool logRegistrations, bool showCameraTestLabel, float logIntervalSeconds)
		{
			return new ScrapDebugOptions(enabled, diagnosticsEnabled, showHeldItems, showZeroValueItems, logRegistrations, showCameraTestLabel, ClampFinite(logIntervalSeconds, 0.25f, 30f));
		}

		private static float ClampFinite(float value, float min, float max)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return min;
			}
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}
	}
	public readonly record struct ScrapHighlightOptions(bool Enabled, float Alpha, float Width, int MaxHighlightedItems)
	{
		private const float MinAlpha = 0f;

		private const float MaxAlpha = 1f;

		private const float MinWidth = 0f;

		private const float MaxWidth = 0.15f;

		private const int MinHighlightedItems = 1;

		private const int MaxHighlightedItemsLimit = 256;

		public static ScrapHighlightOptions Create(bool enabled, float alpha, float width, int maxHighlightedItems)
		{
			return new ScrapHighlightOptions(enabled, ClampFinite(alpha, 0f, 1f), ClampFinite(width, 0f, 0.15f), Clamp(maxHighlightedItems, 1, 256));
		}

		private static float ClampFinite(float value, float min, float max)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return min;
			}
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}

		private static int Clamp(int value, int min, int max)
		{
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}
	}
	public enum ScrapItemNameLanguage
	{
		Auto,
		Chinese,
		English
	}
	public readonly record struct ScrapItemNameOptions(bool ShowItemNames, ScrapItemNameLanguage Language)
	{
		public static ScrapItemNameOptions Default { get; } = new ScrapItemNameOptions(ShowItemNames: true, ScrapItemNameLanguage.Auto);

		public static ScrapItemNameOptions Create(bool showItemNames, string? language)
		{
			return new ScrapItemNameOptions(showItemNames, ParseLanguage(language));
		}

		public static ScrapItemNameLanguage ParseLanguage(string? value)
		{
			if (!Enum.TryParse<ScrapItemNameLanguage>(value, ignoreCase: true, out var result))
			{
				return ScrapItemNameLanguage.Auto;
			}
			return result;
		}
	}
	public readonly record struct ScrapItemSnapshot(int ScrapValue, float DistanceSquaredToPlayer, bool IsHeld, bool IsHeldByEnemy, bool IsDeactivated, bool IsPocketed, bool IsUsedUp);
	public readonly record struct ScrapLabelCandidate(int Id, float ScreenX, float ScreenY, float DistanceToCamera, int ScrapValue, bool WasVisible);
	public readonly record struct ScrapLabelLayoutOptions(bool Enabled, float LabelWidth, float LabelHeight, float MinGap, int MaxOffsetSlots)
	{
		public static ScrapLabelLayoutOptions Default { get; } = Create(enabled: true, 72f, 26f, 6f, 6);

		public static ScrapLabelLayoutOptions ForItemNames(bool showItemNames)
		{
			if (!showItemNames)
			{
				return Default;
			}
			return Create(enabled: true, 220f, 96f, 10f, 6);
		}

		public static ScrapLabelLayoutOptions Create(bool enabled, float labelWidth, float labelHeight, float minGap, int maxOffsetSlots)
		{
			return new ScrapLabelLayoutOptions(enabled, ClampFinite(labelWidth, 24f, 240f), ClampFinite(labelHeight, 12f, 120f), ClampFinite(minGap, 0f, 64f), (maxOffsetSlots >= 0) ? maxOffsetSlots : 0);
		}

		private static float ClampFinite(float value, float min, float max)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return min;
			}
			if (value < min)
			{
				return min;
			}
			if (!(value > max))
			{
				return value;
			}
			return max;
		}
	}
	public sealed class ScrapLabelLayoutResolver
	{
		private sealed class IndexPriorityComparer : IComparer<int>
		{
			private IReadOnlyList<ScrapLabelCandidate>? candidates;

			private int[]? distanceBuckets;

			public void Reset(IReadOnlyList<ScrapLabelCandidate> candidates, int[] distanceBuckets)
			{
				this.candidates = candidates;
				this.distanceBuckets = distanceBuckets;
			}

			public void Clear()
			{
				candidates = null;
				distanceBuckets = null;
			}

			public int Compare(int leftIndex, int rightIndex)
			{
				IReadOnlyList<ScrapLabelCandidate> readOnlyList = candidates;
				int[] array = distanceBuckets;
				return ComparePriority(readOnlyList[leftIndex], readOnlyList[rightIndex], array[leftIndex], array[rightIndex]);
			}
		}

		private const float DistancePriorityBucketSize = 0.25f;

		private static readonly (float X, float Y)[] OffsetSlots = new(float, float)[7]
		{
			(0f, 0f),
			(-0.65f, 0.65f),
			(0.65f, 0.65f),
			(0f, 1.25f),
			(-1.05f, 0f),
			(1.05f, 0f),
			(0f, 1.9f)
		};

		private ScrapLabelLayoutOptions options;

		private readonly List<ScrapLabelPlacement> accepted = new List<ScrapLabelPlacement>();

		private readonly IndexPriorityComparer indexPriorityComparer = new IndexPriorityComparer();

		private int[] sortedIndexes = Array.Empty<int>();

		private int[] distanceBuckets = Array.Empty<int>();

		public ScrapLabelLayoutResolver(ScrapLabelLayoutOptions options)
		{
			this.options = options;
		}

		public void UpdateOptions(ScrapLabelLayoutOptions options)
		{
			this.options = options;
		}

		public ScrapLabelPlacement[] Resolve(IReadOnlyList<ScrapLabelCandidate> candidates, int maxVisibleLabels)
		{
			if (candidates == null)
			{
				throw new ArgumentNullException("candidates");
			}
			List<ScrapLabelPlacement> list = new List<ScrapLabelPlacement>(candidates.Count);
			ResolveInto(candidates, maxVisibleLabels, list);
			return list.ToArray();
		}

		public void ResolveInto(IReadOnlyList<ScrapLabelCandidate> candidates, int maxVisibleLabels, List<ScrapLabelPlacement> results)
		{
			if (candidates == null)
			{
				throw new ArgumentNullException("candidates");
			}
			if (results == null)
			{
				throw new ArgumentNullException("results");
			}
			accepted.Clear();
			results.Clear();
			EnsureSortBufferCapacity(candidates.Count);
			if (results.Capacity < candidates.Count)
			{
				results.Capacity = candidates.Count;
			}
			for (int i = 0; i < candidates.Count; i++)
			{
				results.Add(default(ScrapLabelPlacement));
				sortedIndexes[i] = i;
				distanceBuckets[i] = GetDistancePriorityBucket(candidates[i].DistanceToCamera);
			}
			indexPriorityComparer.Reset(candidates, distanceBuckets);
			try
			{
				Array.Sort(sortedIndexes, 0, candidates.Count, indexPriorityComparer);
				int num = 0;
				for (int j = 0; j < candidates.Count; j++)
				{
					int index = sortedIndexes[j];
					ScrapLabelCandidate candidate = candidates[index];
					if (num >= maxVisibleLabels)
					{
						results[index] = Hidden(candidate);
						continue;
					}
					if (!options.Enabled)
					{
						ScrapLabelPlacement item = (results[index] = Visible(candidate, candidate.ScreenX, candidate.ScreenY, 0));
						accepted.Add(item);
						num++;
						continue;
					}
					bool flag = false;
					int num2 = Math.Min(options.MaxOffsetSlots, OffsetSlots.Length - 1);
					for (int k = 0; k <= num2; k++)
					{
						(float, float) tuple = OffsetSlots[k];
						float screenX = candidate.ScreenX + tuple.Item1 * (options.LabelWidth + options.MinGap);
						float screenY = candidate.ScreenY + tuple.Item2 * (options.LabelHeight + options.MinGap);
						ScrapLabelPlacement scrapLabelPlacement2 = Visible(candidate, screenX, screenY, k);
						if (!OverlapsAccepted(scrapLabelPlacement2))
						{
							results[index] = scrapLabelPlacement2;
							accepted.Add(scrapLabelPlacement2);
							num++;
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						results[index] = Hidden(candidate);
					}
				}
			}
			finally
			{
				accepted.Clear();
				indexPriorityComparer.Clear();
			}
		}

		private void EnsureSortBufferCapacity(int candidateCount)
		{
			if (sortedIndexes.Length < candidateCount)
			{
				Array.Resize(ref sortedIndexes, candidateCount);
				Array.Resize(ref distanceBuckets, candidateCount);
			}
		}

		private bool OverlapsAccepted(ScrapLabelPlacement placement)
		{
			for (int i = 0; i < accepted.Count; i++)
			{
				if (placement.Overlaps(accepted[i], options.MinGap))
				{
					return true;
				}
			}
			return false;
		}

		private ScrapLabelPlacement Visible(ScrapLabelCandidate candidate, float screenX, float screenY, int slotIndex)
		{
			return new ScrapLabelPlacement(candidate.Id, IsVisible: true, screenX, screenY, options.LabelWidth, options.LabelHeight, slotIndex);
		}

		private static ScrapLabelPlacement Hidden(ScrapLabelCandidate candidate)
		{
			return new ScrapLabelPlacement(candidate.Id, IsVisible: false, candidate.ScreenX, candidate.ScreenY, 0f, 0f, -1);
		}

		private static int ComparePriority(ScrapLabelCandidate left, ScrapLabelCandidate right, int leftDistanceBucket, int rightDistanceBucket)
		{
			int num = leftDistanceBucket.CompareTo(rightDistanceBucket);
			if (num != 0)
			{
				return num;
			}
			int num2 = right.ScrapValue.CompareTo(left.ScrapValue);
			if (num2 != 0)
			{
				return num2;
			}
			int num3 = right.WasVisible.CompareTo(left.WasVisible);
			if (num3 != 0)
			{
				return num3;
			}
			return left.Id.CompareTo(right.Id);
		}

		private static int GetDistancePriorityBucket(float distance)
		{
			if (float.IsNaN(distance))
			{
				return int.MaxValue;
			}
			return (int)MathF.Floor(distance / 0.25f);
		}
	}
	public readonly record struct ScrapLabelPlacement(int Id, bool IsVisible, float ScreenX, float ScreenY, float Width, float Height, int SlotIndex)
	{
		public bool Overlaps(ScrapLabelPlacement other, float minGap)
		{
			if (!IsVisible || !other.IsVisible)
			{
				return false;
			}
			float num = Width * 0.5f;
			float num2 = Height * 0.5f;
			float num3 = other.Width * 0.5f;
			float num4 = other.Height * 0.5f;
			if (MathF.Abs(ScreenX - other.ScreenX) < num + num3 + minGap)
			{
				return MathF.Abs(ScreenY - other.ScreenY) < num2 + num4 + minGap;
			}
			return false;
		}
	}
	public readonly record struct ScrapLabelPreCandidate(int Id, float DistanceSquaredToPlayer, int ScrapValue, bool WasVisible);
	public static class ScrapLabelPreCandidatePriority
	{
		private const float DistanceSquaredPriorityBucketSize = 0.25f;

		public static bool IsHigherPriority(ScrapLabelPreCandidate left, ScrapLabelPreCandidate right)
		{
			return Compare(left, right) < 0;
		}

		public static int Compare(ScrapLabelPreCandidate left, ScrapLabelPreCandidate right)
		{
			int num = GetDistancePriorityBucket(left.DistanceSquaredToPlayer).CompareTo(GetDistancePriorityBucket(right.DistanceSquaredToPlayer));
			if (num != 0)
			{
				return num;
			}
			int num2 = right.ScrapValue.CompareTo(left.ScrapValue);
			if (num2 != 0)
			{
				return num2;
			}
			int num3 = right.WasVisible.CompareTo(left.WasVisible);
			if (num3 != 0)
			{
				return num3;
			}
			return left.Id.CompareTo(right.Id);
		}

		private static int GetDistancePriorityBucket(float distanceSquared)
		{
			if (float.IsNaN(distanceSquared) || float.IsInfinity(distanceSquared))
			{
				return int.MaxValue;
			}
			return (int)MathF.Floor(distanceSquared / 0.25f);
		}
	}
	public static class ScrapPriceText
	{
		public static string Format(int value)
		{
			return "$" + value.ToString(CultureInfo.InvariantCulture);
		}
	}
	public enum ScrapRevealActivationMode
	{
		VanillaScan,
		Always
	}
	public static class ScrapRevealActivationModeParser
	{
		public static ScrapRevealActivationMode Parse(string? value)
		{
			if (string.Equals(value, "Always", StringComparison.OrdinalIgnoreCase))
			{
				return ScrapRevealActivationMode.Always;
			}
			return ScrapRevealActivationMode.VanillaScan;
		}
	}
	public sealed class ScrapScanPerformanceOptions
	{
		public bool OptimizeVanillaScan { get; }

		private ScrapScanPerformanceOptions(bool optimizeVanillaScan)
		{
			OptimizeVanillaScan = optimizeVanillaScan;
		}

		public static ScrapScanPerformanceOptions Create(bool optimizeVanillaScan)
		{
			return new ScrapScanPerformanceOptions(optimizeVanillaScan);
		}
	}
	public sealed class ScrapScanRevealState
	{
		public void Trigger(ScrapVisibilityOptions options, float currentTime)
		{
		}

		public void Reset()
		{
		}

		public bool IsActive(ScrapVisibilityOptions options, float currentTime)
		{
			return options.ActivationMode == ScrapRevealActivationMode.Always;
		}
	}
	public static class ScrapScanValueText
	{
		public const string UnknownValue = "???";

		public static bool HasUnknownValue(string? text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			return text.Contains("???");
		}

		public static bool TryParseKnownValue(string? text, out int value)
		{
			value = 0;
			if (string.IsNullOrEmpty(text) || HasUnknownValue(text))
			{
				return false;
			}
			bool flag = false;
			bool flag2 = false;
			foreach (char c in text)
			{
				if (!flag)
				{
					flag = c == '$';
				}
				else if (c < '0' || c > '9')
				{
					if ((!flag2 || (c != ',' && c != ' ' && c != '_')) && flag2)
					{
						break;
					}
				}
				else
				{
					flag2 = true;
					value = value * 10 + c - 48;
				}
			}
			return flag2;
		}
	}
	public readonly record struct ScrapValueColorOptions(bool Enabled, int LowValueMax, int MediumValueMax, int HighValueMax, int VeryHighValueMax)
	{
		private const int MinThreshold = 0;

		private const int MaxThreshold = 9999;

		public static ScrapValueColorOptions Create(bool enabled, int lowValueMax, int mediumValueMax, int highValueMax, int veryHighValueMax)
		{
			int num = Clamp(lowValueMax, 0, 9999);
			int num2 = Clamp(mediumValueMax, num, 9999);
			int num3 = Clamp(highValueMax, num2, 9999);
			int veryHighValueMax2 = Clamp(veryHighValueMax, num3, 9999);
			return new ScrapValueColorOptions(enabled, num, num2, num3, veryHighValueMax2);
		}

		public ScrapValueColorTier ResolveTier(bool hasUnknownValue, int value)
		{
			if (hasUnknownValue)
			{
				return ScrapValueColorTier.Unknown;
			}
			if (value <= LowValueMax)
			{
				return ScrapValueColorTier.Low;
			}
			if (value <= MediumValueMax)
			{
				return ScrapValueColorTier.Medium;
			}
			if (value <= HighValueMax)
			{
				return ScrapValueColorTier.High;
			}
			if (value > VeryHighValueMax)
			{
				return ScrapValueColorTier.Jackpot;
			}
			return ScrapValueColorTier.VeryHigh;
		}

		private static int Clamp(int value, int min, int max)
		{
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}
	}
	public enum ScrapValueColorTier
	{
		Unknown,
		Low,
		Medium,
		High,
		VeryHigh,
		Jackpot
	}
	public sealed class ScrapVisibilityOptions
	{
		private const float MinRevealRadius = 1f;

		private const float MaxRevealRadius = 100f;

		private const float DefaultScanRevealDurationSeconds = 10f;

		private const float MinScanRevealDurationSeconds = 0.5f;

		private const float MaxScanRevealDurationSeconds = 60f;

		private const float MinUpdateIntervalSeconds = 0.05f;

		private const float MaxUpdateIntervalSeconds = 1f;

		private const int MinVisibleLabels = 1;

		private const int MaxVisibleLabelsLimit = 256;

		public bool Enabled { get; }

		public float RevealRadius { get; }

		public float RevealRadiusSquared { get; }

		public ScrapRevealActivationMode ActivationMode { get; }

		public float ScanRevealDurationSeconds { get; }

		public float UpdateIntervalSeconds { get; }

		public int MaxVisibleLabels { get; }

		private ScrapVisibilityOptions(bool enabled, float revealRadius, ScrapRevealActivationMode activationMode, float scanRevealDurationSeconds, float updateIntervalSeconds, int maxVisibleLabels)
		{
			Enabled = enabled;
			RevealRadius = revealRadius;
			RevealRadiusSquared = revealRadius * revealRadius;
			ActivationMode = activationMode;
			ScanRevealDurationSeconds = scanRevealDurationSeconds;
			UpdateIntervalSeconds = updateIntervalSeconds;
			MaxVisibleLabels = maxVisibleLabels;
		}

		public static ScrapVisibilityOptions Create(bool enabled, float revealRadius, float updateIntervalSeconds, int maxVisibleLabels, string activationMode = "VanillaScan", float scanRevealDurationSeconds = 10f)
		{
			return new ScrapVisibilityOptions(enabled, ClampFinite(revealRadius, 1f, 100f), ScrapRevealActivationModeParser.Parse(activationMode), ClampFiniteOrDefault(scanRevealDurationSeconds, 0.5f, 60f, 10f), ClampFinite(updateIntervalSeconds, 0.05f, 1f), Clamp(maxVisibleLabels, 1, 256));
		}

		private static float ClampFiniteOrDefault(float value, float min, float max, float fallback)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return fallback;
			}
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}

		private static float ClampFinite(float value, float min, float max)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				return min;
			}
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}

		private static int Clamp(int value, int min, int max)
		{
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}
	}
	public sealed class ScrapVisibilityRules
	{
		private readonly ScrapVisibilityOptions options;

		public ScrapDebugOptions Debug { get; }

		public ScrapVisibilityRules(ScrapVisibilityOptions options)
			: this(options, ScrapDebugOptions.Disabled)
		{
		}

		public ScrapVisibilityRules(ScrapVisibilityOptions options, ScrapDebugOptions debug)
		{
			this.options = options;
			Debug = debug;
		}

		public bool ShouldShow(ScrapItemSnapshot item)
		{
			if (!ShouldShowVanillaScanned(item))
			{
				return false;
			}
			return item.DistanceSquaredToPlayer <= options.RevealRadiusSquared;
		}

		public bool ShouldShowVanillaScanned(ScrapItemSnapshot item)
		{
			if (!options.Enabled)
			{
				return false;
			}
			if (item.ScrapValue <= 0 && (!Debug.Enabled || !Debug.ShowZeroValueItems))
			{
				return false;
			}
			if (item.IsDeactivated || item.IsUsedUp)
			{
				return false;
			}
			if ((item.IsHeld || item.IsHeldByEnemy || item.IsPocketed) && (!Debug.Enabled || !Debug.ShowHeldItems))
			{
				return false;
			}
			return true;
		}
	}
}
namespace Auuueser.ScanValue.Core.Configuration
{
	public static class ChineseProjectDetection
	{
		private const string CurrentKnownGuid = "cn.codex.v81testchn";

		private const string PackageName = "LC_Chinese_Project";

		private const string RepositoryUrl = "github.com/Auuueser/LC-Chinese-Project";

		public static bool IsChineseProjectPlugin(string? pluginGuid, string? pluginName, string? pluginLocation)
		{
			if (EqualsIgnoreCase(pluginGuid, "cn.codex.v81testchn"))
			{
				return true;
			}
			if (ContainsIgnoreCase(pluginName, "LC Chinese Project") || ContainsIgnoreCase(pluginName, "Chinese Project") || ContainsIgnoreCase(pluginName, "V81 TEST CHN"))
			{
				return true;
			}
			if (!ContainsIgnoreCase(pluginLocation, "LC_Chinese_Project") && !ContainsIgnoreCase(pluginLocation, "LC-Chinese-Project"))
			{
				return ContainsIgnoreCase(pluginLocation, "LC Chinese Project");
			}
			return true;
		}

		public static bool ContainsChineseProjectManifestText(string? manifestText)
		{
			if (!ContainsIgnoreCase(manifestText, "LC_Chinese_Project") && !ContainsIgnoreCase(manifestText, "LC Chinese Project") && !ContainsIgnoreCase(manifestText, "LC-Chinese-Project"))
			{
				return ContainsIgnoreCase(manifestText, "github.com/Auuueser/LC-Chinese-Project");
			}
			return true;
		}

		public static bool ContainsChineseConfigSections(string? configText)
		{
			if (!ContainsIgnoreCase(configText, "[通用]") && !ContainsIgnoreCase(configText, "[可见性]") && !ContainsIgnoreCase(configText, "[性能]") && !ContainsIgnoreCase(configText, "[标签]"))
			{
				return ContainsIgnoreCase(configText, "[调试]");
			}
			return true;
		}

		private static bool EqualsIgnoreCase(string? value, string expected)
		{
			return string.Equals(value, expected, StringComparison.OrdinalIgnoreCase);
		}

		private static bool ContainsIgnoreCase(string? value, string expected)
		{
			if (value != null)
			{
				return value.IndexOf(expected, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}
	}
	public enum ConfigLanguage
	{
		English,
		Chinese
	}
	public static class ConfigTextCatalog
	{
		private static readonly ConfigTexts English = new ConfigTexts("General", "Visibility", "Performance", "Label", "Highlight", "Debug", "Enable automatic scrap value labels. Applied immediately.", "Player-centered reveal radius in meters. Applied immediately.", "When labels appear: VanillaScan mirrors the vanilla right-click scan UI; Always keeps the old automatic behavior. Old ScanOnly values are treated as VanillaScan. Applied immediately.", "Legacy setting kept for old configs. VanillaScan follows the vanilla scan UI and does not use a timed reveal window. Applied immediately.", "Seconds between visibility refreshes. Higher values reduce CPU work. Applied immediately.", "Maximum labels shown at once. Applied immediately.", "Vertical world-space offset above each scrap object. Applied immediately.", "World-space scale for each label. Applied immediately.", "TextMeshPro font size. Applied immediately.", "HTML color for the price text, for example #FFD447. Applied immediately.", "HTML color for the text outline. Applied immediately.", "Text outline width from 0 to 0.5. Applied immediately.", "Highlight scanned scrap object outlines. Applied immediately.", "HTML color for scanned scrap outlines, for example #FFD447. Applied immediately.", "Opacity for scanned scrap outlines from 0 to 1. Applied immediately.", "World-space outline proxy expansion from 0 to 0.15. Applied immediately.", "Maximum scanned scrap objects highlighted at once. Applied immediately.", "Enable diagnostic and test-only behavior. Keep disabled for normal play.", "Debug only: log low-frequency camera, registry, filtering, layout, and pool counters. Requires debug mode. Applied immediately.", "Show labels for held or pocketed items while debug mode is enabled. Applied immediately.", "Show $0 labels for registered items while debug mode is enabled. Applied immediately.", "Log item registration events while debug mode is enabled. Applied immediately.", "Debug only: render a fixed $TEST price label in front of the active camera. Requires debug mode. Applied immediately.", "Seconds between debug visibility summaries. Applied immediately.");

		private static readonly ConfigTexts Chinese = new ConfigTexts("通用", "可见性", "性能", "标签", "高光", "调试", "启用自动废料价格标签。保存后立即生效。", "以本地玩家为中心的显示半径,单位为米。保存后立即生效。", "标签显示方式:VanillaScan 跟随原版右键 scan UI;Always 保留旧的自动显示行为。旧的 ScanOnly 会按 VanillaScan 处理。保存后立即生效。", "兼容旧配置保留的设置。VanillaScan 跟随原版 scan UI,不再使用计时显示窗口。保存后立即生效。", "刷新可见性检测的间隔秒数;数值越高,CPU 开销越低。保存后立即生效。", "同一时间最多显示的价格标签数量。保存后立即生效。", "价格标签相对废料物体向上的世界空间偏移。保存后立即生效。", "每个价格标签的世界空间缩放。保存后立即生效。", "TextMeshPro 字体大小。保存后立即生效。", "价格文字的 HTML 颜色,例如 #FFD447。保存后立即生效。", "文字描边的 HTML 颜色。保存后立即生效。", "文字描边宽度,范围 0 到 0.5。保存后立即生效。", "启用 scan 时废料物体轮廓高光。保存后立即生效。", "scan 时废料轮廓高光的 HTML 颜色,例如 #FFD447。保存后立即生效。", "scan 时废料轮廓高光透明度,范围 0 到 1。保存后立即生效。", "scan 时废料轮廓高光代理的外扩宽度,范围 0 到 0.15。保存后立即生效。", "同一时间最多高光显示的废料数量。保存后立即生效。", "启用诊断和仅测试用行为。正常游玩时保持关闭。", "仅调试:低频输出相机、注册、过滤、布局和标签池计数日志。需要启用调试模式。保存后立即生效。", "调试模式开启时,显示被持有或放入口袋的物品价格。保存后立即生效。", "调试模式开启时,为已注册物品显示 $0 标签。保存后立即生效。", "调试模式开启时,输出物品注册日志。保存后立即生效。", "仅调试:在活动相机前方渲染固定 $TEST 价格标签。需要启用调试模式。保存后立即生效。", "两次调试可见性统计之间的秒数。保存后立即生效。", "在废料价值标签上方显示物品名称。保存后立即生效。", "物品名称语言:Auto、Chinese 或 English。保存后立即生效。", "根据扫描到的废料价值为标签文字和轮廓高光变色。保存后立即生效。", "低价值颜色档的最高价格。保存后立即生效。", "中价值颜色档的最高价格。保存后立即生效。", "高价值颜色档的最高价格。保存后立即生效。", "很高价值颜色档的最高价格。超过该值时使用极品颜色。保存后立即生效。", "未知价值(例如未拔下 Apparatus 的 ???)使用的 HTML 颜色。保存后立即生效。", "低价值废料标签文字和轮廓高光的 HTML 颜色。保存后立即生效。", "中价值废料标签文字和轮廓高光的 HTML 颜色。保存后立即生效。", "高价值废料标签文字和轮廓高光的 HTML 颜色。保存后立即生效。", "很高价值废料标签文字和轮廓高光的 HTML 颜色。保存后立即生效。", "极品价值废料标签文字和轮廓高光的 HTML 颜色。保存后立即生效。", "优化原版右键 scan:缓存 scan UI 组件并避免重复文本重建。保存后立即生效。");

		public static ConfigTexts Get(ConfigLanguage language)
		{
			if (language != ConfigLanguage.Chinese)
			{
				return English;
			}
			return Chinese;
		}
	}
	public sealed class ConfigTexts
	{
		public string GeneralSection { get; }

		public string VisibilitySection { get; }

		public string PerformanceSection { get; }

		public string LabelSection { get; }

		public string HighlightSection { get; }

		public string DebugSection { get; }

		public string EnabledDescription { get; }

		public string RevealRadiusDescription { get; }

		public string ActivationModeDescription { get; }

		public string ScanRevealDurationSecondsDescription { get; }

		public string UpdateIntervalSecondsDescription { get; }

		public string MaxVisibleLabelsDescription { get; }

		public string HeightOffsetDescription { get; }

		public string WorldScaleDescription { get; }

		public string FontSizeDescription { get; }

		public string LabelColorDescription { get; }

		public string OutlineColorDescription { get; }

		public string OutlineWidthDescription { get; }

		public string HighlightEnabledDescription { get; }

		public string HighlightColorDescription { get; }

		public string HighlightAlphaDescription { get; }

		public string HighlightWidthDescription { get; }

		public string MaxHighlightedItemsDescription { get; }

		public string ShowItemNamesDescription { get; }

		public string ItemNameLanguageDescription { get; }

		public string ValueBasedColorsEnabledDescription { get; }

		public string LowValueMaxDescription { get; }

		public string MediumValueMaxDescription { get; }

		public string HighValueMaxDescription { get; }

		public string VeryHighValueMaxDescription { get; }

		public string UnknownValueColorDescription { get; }

		public string LowValueColorDescription { get; }

		public string MediumValueColorDescription { get; }

		public string HighValueColorDescription { get; }

		public string VeryHighValueColorDescription { get; }

		public string JackpotValueColorDescription { get; }

		public string OptimizeVanillaScanDescription { get; }

		public string DebugEnabledDescription { get; }

		public string DebugDiagnosticsEnabledDescription { get; }

		public string DebugShowHeldItemsDescription { get; }

		public string DebugShowZeroValueItemsDescription { get; }

		public string DebugLogRegistrationsDescription { get; }

		public string DebugShowCameraTestLabelDescription { get; }

		public string DebugLogIntervalSecondsDescription { get; }

		public ConfigTexts(string generalSection, string visibilitySection, string performanceSection, string labelSection, string highlightSection, string debugSection, string enabledDescription, string revealRadiusDescription, string activationModeDescription, string scanRevealDurationSecondsDescription, string updateIntervalSecondsDescription, string maxVisibleLabelsDescription, string heightOffsetDescription, string worldScaleDescription, string fontSizeDescription, string labelColorDescription, string outlineColorDescription, string outlineWidthDescription, string highlightEnabledDescription, string highlightColorDescription, string highlightAlphaDescription, string highlightWidthDescription, string maxHighlightedItemsDescription, string debugEnabledDescription, string debugDiagnosticsEnabledDescription, string debugShowHeldItemsDescription, string debugShowZeroValueItemsDescription, string debugLogRegistrationsDescription, string debugShowCameraTestLabelDescription, string debugLogIntervalSecondsDescription, string showItemNamesDescription = "Show the item name above the scrap value label. Applied immediately.", string itemNameLanguageDescription = "Item-name language: Auto, Chinese, or English. Applied immediately.", string valueBasedColorsEnabledDescription = "Color scrap labels and scan outlines by the scanned scrap value. Applied immediately.", string lowValueMaxDescription = "Maximum value for the low-value color tier. Applied immediately.", string mediumValueMaxDescription = "Maximum value for the medium-value color tier. Applied immediately.", string highValueMaxDescription = "Maximum value for the high-value color tier. Applied immediately.", string veryHighValueMaxDescription = "Maximum value for the very-high-value color tier. Values above this use the jackpot color. Applied immediately.", string unknownValueColorDescription = "HTML color for unknown scan values such as docked Apparatus ???. Applied immediately.", string lowValueColorDescription = "HTML color for low-value scrap labels and scan outlines. Applied immediately.", string mediumValueColorDescription = "HTML color for medium-value scrap labels and scan outlines. Applied immediately.", string highValueColorDescription = "HTML color for high-value scrap labels and scan outlines. Applied immediately.", string veryHighValueColorDescription = "HTML color for very-high-value scrap labels and scan outlines. Applied immediately.", string jackpotValueColorDescription = "HTML color for jackpot-value scrap labels and scan outlines. Applied immediately.", string optimizeVanillaScanDescription = "Optimize the vanilla right-click scan by caching scan UI components and avoiding repeated text rebuilds. Applied immediately.")
		{
			GeneralSection = generalSection;
			VisibilitySection = visibilitySection;
			PerformanceSection = performanceSection;
			LabelSection = labelSection;
			HighlightSection = highlightSection;
			DebugSection = debugSection;
			EnabledDescription = enabledDescription;
			RevealRadiusDescription = revealRadiusDescription;
			ActivationModeDescription = activationModeDescription;
			ScanRevealDurationSecondsDescription = scanRevealDurationSecondsDescription;
			UpdateIntervalSecondsDescription = updateIntervalSecondsDescription;
			MaxVisibleLabelsDescription = maxVisibleLabelsDescription;
			HeightOffsetDescription = heightOffsetDescription;
			WorldScaleDescription = worldScaleDescription;
			FontSizeDescription = fontSizeDescription;
			LabelColorDescription = labelColorDescription;
			OutlineColorDescription = outlineColorDescription;
			OutlineWidthDescription = outlineWidthDescription;
			HighlightEnabledDescription = highlightEnabledDescription;
			HighlightColorDescription = highlightColorDescription;
			HighlightAlphaDescription = highlightAlphaDescription;
			HighlightWidthDescription = highlightWidthDescription;
			MaxHighlightedItemsDescription = maxHighlightedItemsDescription;
			ShowItemNamesDescription = showItemNamesDescription;
			ItemNameLanguageDescription = itemNameLanguageDescription;
			ValueBasedColorsEnabledDescription = valueBasedColorsEnabledDescription;
			LowValueMaxDescription = lowValueMaxDescription;
			MediumValueMaxDescription = mediumValueMaxDescription;
			HighValueMaxDescription = highValueMaxDescription;
			VeryHighValueMaxDescription = veryHighValueMaxDescription;
			UnknownValueColorDescription = unknownValueColorDescription;
			LowValueColorDescription = lowValueColorDescription;
			MediumValueColorDescription = mediumValueColorDescription;
			HighValueColorDescription = highValueColorDescription;
			VeryHighValueColorDescription = veryHighValueColorDescription;
			JackpotValueColorDescription = jackpotValueColorDescription;
			OptimizeVanillaScanDescription = optimizeVanillaScanDescription;
			DebugEnabledDescription = debugEnabledDescription;
			DebugDiagnosticsEnabledDescription = debugDiagnosticsEnabledDescription;
			DebugShowHeldItemsDescription = debugShowHeldItemsDescription;
			DebugShowZeroValueItemsDescription = debugShowZeroValueItemsDescription;
			DebugLogRegistrationsDescription = debugLogRegistrationsDescription;
			DebugShowCameraTestLabelDescription = debugShowCameraTestLabelDescription;
			DebugLogIntervalSecondsDescription = debugLogIntervalSecondsDescription;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	internal static class IsExternalInit
	{
	}
}

BepInEx/plugins/ScanValue/ScanValue.dll

Decompiled a day ago
using System;
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 Auuueser.ScanValue.Configuration;
using Auuueser.ScanValue.Core.Configuration;
using Auuueser.ScanValue.Core.Domain;
using Auuueser.ScanValue.Core.Localization;
using Auuueser.ScanValue.Game;
using Auuueser.ScanValue.Localization;
using Auuueser.ScanValue.Presentation;
using Auuueser.ScanValue.Runtime;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

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

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Auuueser.ScanValue
{
	[BepInPlugin("com.auuueser.lethalcompany.scanvalue", "ScanValue", "0.0.1")]
	[BepInProcess("Lethal Company.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private ScanValueRuntime? runtime;

		private bool applicationQuitting;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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)
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigLanguage language = ChineseProjectLanguageDetector.Detect(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			if (ConfigLanguageFileMigrator.Normalize(((BaseUnityPlugin)this).Config.ConfigFilePath, language, ((BaseUnityPlugin)this).Logger))
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			ModConfig config = ModConfig.Bind(((BaseUnityPlugin)this).Config, language);
			runtime = ScanValueRuntime.Start(config, ((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ScanValue 0.0.1 loaded.");
		}

		private void OnDestroy()
		{
			if (!applicationQuitting && Application.isPlaying)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"ScanValue received early OnDestroy while the application is still running; preserving runtime.");
			}
			else
			{
				DisposeRuntime();
			}
		}

		private void OnApplicationQuit()
		{
			applicationQuitting = true;
			DisposeRuntime();
		}

		private void DisposeRuntime()
		{
			runtime?.Dispose();
			runtime = null;
		}
	}
	internal static class PluginInfo
	{
		public const string PluginGuid = "com.auuueser.lethalcompany.scanvalue";

		public const string PluginName = "ScanValue";

		public const string PluginVersion = "0.0.1";
	}
}
namespace Auuueser.ScanValue.Runtime
{
	internal sealed class ScanValueRuntime : IDisposable
	{
		private static GameObject? runtimeObject;

		private static ScrapVisibilityController? runtimeController;

		private static ScrapObjectRegistry? registry;

		private static ScrapObjectPatcher? patcher;

		private static VanillaScanPatcher? scanPatcher;

		private static ScrapPricePresenter? presenter;

		private static ScrapHighlightPresenter? highlightPresenter;

		private static ScrapItemNameLocalizer? nameLocalizer;

		private readonly GameObject host;

		private bool disposed;

		private ScanValueRuntime(GameObject host)
		{
			this.host = host;
		}

		public static ScanValueRuntime Start(ModConfig config, ManualLogSource logger)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)runtimeObject == (Object)null)
			{
				runtimeObject = new GameObject("ScanValue.Runtime");
				((Object)runtimeObject).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)runtimeObject);
			}
			else if (!runtimeObject.activeSelf)
			{
				runtimeObject.SetActive(true);
			}
			if (nameLocalizer == null)
			{
				nameLocalizer = ScrapItemNameLocalizer.Load(logger);
			}
			if (registry == null)
			{
				registry = new ScrapObjectRegistry(logger, nameLocalizer);
			}
			if (presenter == null)
			{
				presenter = new ScrapPricePresenter(runtimeObject.transform, nameLocalizer);
			}
			if (highlightPresenter == null)
			{
				highlightPresenter = new ScrapHighlightPresenter();
			}
			if (patcher == null)
			{
				patcher = new ScrapObjectPatcher(registry, logger, ReapplyHighlightVisibility);
			}
			runtimeController = runtimeObject.GetComponent<ScrapVisibilityController>();
			if ((Object)(object)runtimeController == (Object)null)
			{
				runtimeController = runtimeObject.AddComponent<ScrapVisibilityController>();
			}
			runtimeController.Initialize(config, logger, registry, presenter, highlightPresenter, new LocalPlayerProvider());
			if (scanPatcher == null)
			{
				scanPatcher = new VanillaScanPatcher(runtimeController, logger);
			}
			runtimeController.SetEnabled(enabled: true);
			logger.LogInfo((object)"Runtime controller active.");
			return new ScanValueRuntime(runtimeObject);
		}

		private static void ReapplyHighlightVisibility(GrabbableObject item)
		{
			if (registry != null && highlightPresenter != null && registry.TryGet(item, out TrackedScrapItem tracked))
			{
				runtimeController?.MarkVanillaScanVisualStateDirty();
				if (item.isHeld || item.isHeldByEnemy || item.isPocketed || item.deactivated || item.itemUsedUp)
				{
					highlightPresenter.Hide(tracked);
				}
				else
				{
					highlightPresenter.ReapplyVisibilityState(tracked);
				}
			}
		}

		public void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				patcher?.Dispose();
				patcher = null;
				scanPatcher?.Dispose();
				scanPatcher = null;
				registry?.Clear();
				registry = null;
				nameLocalizer = null;
				highlightPresenter?.HideAll();
				highlightPresenter = null;
				presenter = null;
				runtimeController = null;
				if ((Object)(object)host != (Object)null)
				{
					Object.Destroy((Object)(object)host);
				}
				if ((Object)(object)runtimeObject == (Object)(object)host)
				{
					runtimeObject = null;
				}
			}
		}
	}
	internal sealed class ScrapDiagnostics
	{
		private readonly ManualLogSource logger;

		private float nextLogTime;

		public ScrapDiagnostics(ManualLogSource logger)
		{
			this.logger = logger;
		}

		public void LogNoCameraIfDue(ScrapDebugOptions debug, int registered, string reason)
		{
			if (ShouldLog(debug))
			{
				logger.LogInfo((object)$"ScanValue diagnostics: camera=none registered={registered} reason={reason}");
			}
		}

		public void LogScanIfDue(ScrapDebugOptions debug, Camera camera, ScrapDiagnosticCounters counters)
		{
			if (ShouldLog(debug))
			{
				logger.LogInfo((object)($"ScanValue diagnostics: camera={((Object)camera).name} registered={counters.Registered} alive={counters.Alive} candidates={counters.Candidates} shown={counters.Shown} " + $"hiddenNoValue={counters.HiddenNoValue} hiddenState={counters.HiddenState} hiddenDistance={counters.HiddenDistance} hiddenBudget={counters.HiddenBudget} hiddenOverlap={counters.HiddenOverlap} " + $"poolActive={counters.PoolActive} poolIdle={counters.PoolIdle} testLabel={counters.TestLabel}"));
			}
		}

		private bool ShouldLog(ScrapDebugOptions debug)
		{
			if (!debug.ShouldLogDiagnostics || Time.realtimeSinceStartup < nextLogTime)
			{
				return false;
			}
			nextLogTime = Time.realtimeSinceStartup + debug.LogIntervalSeconds;
			return true;
		}
	}
	internal struct ScrapDiagnosticCounters
	{
		public int Registered;

		public int Alive;

		public int Candidates;

		public int Shown;

		public int HiddenNoValue;

		public int HiddenState;

		public int HiddenDistance;

		public int HiddenBudget;

		public int HiddenOverlap;

		public int PoolActive;

		public int PoolIdle;

		public bool TestLabel;
	}
	internal sealed class ScrapVisibilityController : MonoBehaviour
	{
		private const int VisualPrewarmBatchSize = 4;

		private const int LayoutCandidateMargin = 24;

		private const int HighlightPrewarmBatchSize = 2;

		private const int HighlightPrewarmCandidateChecks = 16;

		private ModConfig config;

		private ManualLogSource logger;

		private ScrapObjectRegistry registry;

		private ScrapPricePresenter presenter;

		private ScrapHighlightPresenter highlightPresenter;

		private LocalPlayerProvider localPlayerProvider;

		private ScrapDiagnostics diagnostics;

		private ScrapVisibilityRules rules;

		private ScrapVisibilityRules highlightRules;

		private readonly ScrapLabelLayoutResolver layoutResolver = new ScrapLabelLayoutResolver(ScrapLabelLayoutOptions.Default);

		private readonly List<TrackedScrapItem> preLayoutItems = new List<TrackedScrapItem>(128);

		private readonly List<float> preLayoutDistanceSquares = new List<float>(128);

		private readonly List<bool> preLayoutWasVisible = new List<bool>(128);

		private readonly List<TrackedScrapItem> layoutItems = new List<TrackedScrapItem>(128);

		private readonly List<ScrapLabelCandidate> layoutCandidates = new List<ScrapLabelCandidate>(128);

		private readonly List<ScrapLabelPlacement> layoutPlacements = new List<ScrapLabelPlacement>(128);

		private readonly List<Vector3> layoutAnchors = new List<Vector3>(128);

		private readonly List<TrackedScrapItem> visibleVanillaScanItems = new List<TrackedScrapItem>(32);

		private readonly List<TrackedScrapItem> incomingVanillaScanItems = new List<TrackedScrapItem>(32);

		private int settingsVersion = -1;

		private float nextRefreshTime;

		private float nextPrewarmTime;

		private float nextDebugHeartbeatLogTime;

		private int nextHighlightPrewarmIndex;

		private bool vanillaScanHighlightRefreshRequired = true;

		private bool initialized;

		public bool ShouldSuppressVanillaScanElements
		{
			get
			{
				if (initialized)
				{
					return config.Current.Visibility.Enabled;
				}
				return false;
			}
		}

		public bool ShouldOptimizeVanillaScan
		{
			get
			{
				if (initialized)
				{
					return config.Current.ScanPerformance.OptimizeVanillaScan;
				}
				return false;
			}
		}

		public void Initialize(ModConfig config, ManualLogSource logger, ScrapObjectRegistry registry, ScrapPricePresenter presenter, ScrapHighlightPresenter highlightPresenter, LocalPlayerProvider localPlayerProvider)
		{
			this.config = config;
			this.logger = logger;
			this.registry = registry;
			this.presenter = presenter;
			this.highlightPresenter = highlightPresenter;
			this.localPlayerProvider = localPlayerProvider;
			diagnostics = new ScrapDiagnostics(logger);
			initialized = true;
			RefreshSettingsIfNeeded();
		}

		public void SetEnabled(bool enabled)
		{
			((Component)this).gameObject.SetActive(enabled);
		}

		public void MarkVanillaScanVisualStateDirty()
		{
			if (initialized)
			{
				vanillaScanHighlightRefreshRequired = true;
				nextRefreshTime = 0f;
			}
		}

		public void SetVisibleVanillaScanNodes(Dictionary<RectTransform, ScanNodeProperties> scanNodes)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized)
			{
				return;
			}
			if (scanNodes == null)
			{
				ClearVisibleVanillaScanNodes();
				return;
			}
			ModSettings current = config.Current;
			if (!current.Visibility.Enabled || (int)current.Visibility.ActivationMode != 0)
			{
				ClearVisibleVanillaScanNodes();
				highlightPresenter.HideAll();
				return;
			}
			incomingVanillaScanItems.Clear();
			bool flag = false;
			foreach (KeyValuePair<RectTransform, ScanNodeProperties> scanNode in scanNodes)
			{
				ScanNodeProperties value = scanNode.Value;
				if (!((Object)(object)value == (Object)null) && value.nodeType == 2 && registry.TryGetByScanNode(value, out TrackedScrapItem tracked) && TryApplyScanNodeValue(value, tracked, out var valueChanged))
				{
					if (valueChanged)
					{
						flag = true;
					}
					incomingVanillaScanItems.Add(tracked);
				}
			}
			bool num = !VanillaScanItemsMatch();
			if (num)
			{
				visibleVanillaScanItems.Clear();
				visibleVanillaScanItems.AddRange(incomingVanillaScanItems);
				nextRefreshTime = 0f;
				vanillaScanHighlightRefreshRequired = true;
			}
			if (flag)
			{
				nextRefreshTime = 0f;
			}
			if (num || flag || vanillaScanHighlightRefreshRequired)
			{
				RefreshHighlightedVanillaScanItems(current, incomingVanillaScanItems);
				vanillaScanHighlightRefreshRequired = false;
			}
		}

		public void ClearVisibleVanillaScanNodes()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized)
			{
				return;
			}
			highlightPresenter.HideAll();
			if (visibleVanillaScanItems.Count != 0)
			{
				visibleVanillaScanItems.Clear();
				nextRefreshTime = 0f;
				if ((int)config.Current.Visibility.ActivationMode == 0)
				{
					presenter.HideScrapLabels();
				}
			}
		}

		private void Update()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			if (!initialized)
			{
				return;
			}
			config.ReloadIfChangedOnDisk(Time.realtimeSinceStartup);
			RefreshSettingsIfNeeded();
			ModSettings current = config.Current;
			if (!current.Visibility.Enabled)
			{
				highlightPresenter.HideAll();
				presenter.HideAll();
				LogDebugHeartbeatIfDue(current, null);
				return;
			}
			bool flag = (int)current.Visibility.ActivationMode == 0;
			PrewarmScanVisualCachesIfDue(current, flag);
			if (flag && visibleVanillaScanItems.Count == 0 && !current.Debug.ShouldShowCameraTestLabel && !current.Debug.ShouldLogDiagnostics)
			{
				highlightPresenter.HideAll();
				presenter.HideDebugTestLabel();
				presenter.HideScrapLabels();
				return;
			}
			if (!localPlayerProvider.TryGet(out Vector3 playerPosition, out Camera playerCamera, out string failureReason))
			{
				highlightPresenter.HideAll();
				presenter.HideDebugTestLabel();
				presenter.HideAll();
				diagnostics.LogNoCameraIfDue(current.Debug, registry.Count, failureReason);
				LogDebugHeartbeatIfDue(current, null);
				return;
			}
			if (current.Debug.ShouldShowCameraTestLabel)
			{
				presenter.ShowDebugTestLabel(playerCamera);
			}
			else
			{
				presenter.HideDebugTestLabel();
			}
			LogDebugHeartbeatIfDue(current, playerCamera);
			if (flag && visibleVanillaScanItems.Count == 0)
			{
				highlightPresenter.HideAll();
				presenter.HideScrapLabels();
			}
			else if (!(Time.unscaledTime < nextRefreshTime))
			{
				nextRefreshTime = Time.unscaledTime + current.Visibility.UpdateIntervalSeconds;
				RefreshVisibleLabels(current, playerPosition, playerCamera, flag);
			}
		}

		private void RefreshSettingsIfNeeded()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			if (settingsVersion == config.SettingsVersion)
			{
				return;
			}
			settingsVersion = config.SettingsVersion;
			rules = new ScrapVisibilityRules(config.Current.Visibility, config.Current.Debug);
			highlightRules = new ScrapVisibilityRules(config.Current.Visibility, ScrapDebugOptions.Disabled);
			ScrapLabelLayoutResolver obj = layoutResolver;
			ScrapItemNameOptions itemNames = config.Current.ItemNames;
			obj.UpdateOptions(ScrapLabelLayoutOptions.ForItemNames(((ScrapItemNameOptions)(ref itemNames)).ShowItemNames));
			registry.SetDebugOptions(config.Current.Debug.Enabled && config.Current.Debug.LogRegistrations, config.Current.Debug.Enabled && config.Current.Debug.ShowZeroValueItems);
			presenter.ApplyStyle(config.Current);
			highlightPresenter.ApplyStyle(config.Current);
			vanillaScanHighlightRefreshRequired = true;
			if (config.Current.Visibility.Enabled)
			{
				ScrapHighlightOptions highlight = config.Current.Highlight;
				if (((ScrapHighlightOptions)(ref highlight)).Enabled && (int)config.Current.Visibility.ActivationMode == 0)
				{
					goto IL_0192;
				}
			}
			visibleVanillaScanItems.Clear();
			highlightPresenter.HideAll();
			goto IL_0192;
			IL_0192:
			nextRefreshTime = 0f;
			nextPrewarmTime = 0f;
			if (config.Current.Debug.ShouldLogDiagnostics)
			{
				logger.LogInfo((object)"ScanValue settings reloaded.");
			}
		}

		private void LogDebugHeartbeatIfDue(ModSettings settings, Camera? camera)
		{
			ScrapDebugOptions debug = settings.Debug;
			if (debug.ShouldLogDiagnostics && !(Time.unscaledTime < nextDebugHeartbeatLogTime))
			{
				nextDebugHeartbeatLogTime = Time.unscaledTime + debug.LogIntervalSeconds;
				string arg = (((Object)(object)camera != (Object)null) ? ((Object)camera).name : "none");
				logger.LogInfo((object)($"ScanValue debug heartbeat: enabled={settings.Visibility.Enabled} camera='{arg}' registered={registry.Count} " + $"active={presenter.ActiveCount} testLabel={presenter.DebugTestLabelVisible}"));
			}
		}

		private void PrewarmScanVisualCachesIfDue(ModSettings settings, bool usesVanillaScanNodes)
		{
			if (usesVanillaScanNodes && visibleVanillaScanItems.Count == 0 && !(Time.unscaledTime < nextPrewarmTime))
			{
				nextPrewarmTime = Time.unscaledTime + settings.Visibility.UpdateIntervalSeconds;
				presenter.Prewarm(settings.Visibility.MaxVisibleLabels, 4);
				PrewarmHighlightProxies(settings, 2);
			}
		}

		private void PrewarmHighlightProxies(ModSettings settings, int maxCreatedCount)
		{
			//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_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)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			ScrapHighlightOptions highlight = settings.Highlight;
			if (!((ScrapHighlightOptions)(ref highlight)).Enabled || registry.Count == 0 || maxCreatedCount <= 0)
			{
				return;
			}
			int num = ((registry.Count < 16) ? registry.Count : 16);
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				if (num2 >= maxCreatedCount)
				{
					break;
				}
				if (nextHighlightPrewarmIndex >= registry.Count)
				{
					nextHighlightPrewarmIndex = 0;
				}
				TrackedScrapItem trackedScrapItem = registry[nextHighlightPrewarmIndex];
				nextHighlightPrewarmIndex++;
				if (trackedScrapItem.IsAlive)
				{
					ScrapItemSnapshot val = CreateVanillaScanSnapshot(trackedScrapItem);
					if (highlightRules.ShouldShowVanillaScanned(val) && highlightPresenter.Prewarm(trackedScrapItem, settings))
					{
						num2++;
					}
				}
			}
		}

		private void RefreshVisibleLabels(ModSettings settings, Vector3 playerPosition, Camera playerCamera, bool usesVanillaScanNodes)
		{
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: 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_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_0387: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: 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_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			preLayoutItems.Clear();
			preLayoutDistanceSquares.Clear();
			preLayoutWasVisible.Clear();
			layoutItems.Clear();
			layoutCandidates.Clear();
			layoutAnchors.Clear();
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			int num7 = 0;
			ScrapDebugOptions debug = settings.Debug;
			bool shouldLogDiagnostics = debug.ShouldLogDiagnostics;
			int num8 = settings.Visibility.MaxVisibleLabels + 24;
			int index = -1;
			presenter.BeginFrame();
			int num9 = (usesVanillaScanNodes ? visibleVanillaScanItems.Count : registry.Count);
			for (int i = 0; i < num9; i++)
			{
				TrackedScrapItem trackedScrapItem = (usesVanillaScanNodes ? visibleVanillaScanItems[i] : registry[i]);
				if (!trackedScrapItem.IsAlive)
				{
					continue;
				}
				num2++;
				GrabbableObject item = trackedScrapItem.Item;
				Vector3 val = trackedScrapItem.Transform.position - playerPosition;
				int num10 = (usesVanillaScanNodes ? trackedScrapItem.ScrapValue : item.scrapValue);
				bool flag = usesVanillaScanNodes && trackedScrapItem.HasUnknownValue;
				ScrapItemSnapshot val2 = CreateItemSnapshot(trackedScrapItem, flag ? 1 : num10, ((Vector3)(ref val)).sqrMagnitude);
				if (!(usesVanillaScanNodes ? rules.ShouldShowVanillaScanned(val2) : rules.ShouldShow(val2)))
				{
					if (shouldLogDiagnostics)
					{
						if (((ScrapItemSnapshot)(ref val2)).ScrapValue <= 0 && !debug.ShowZeroValueItems)
						{
							num3++;
						}
						else if (((ScrapItemSnapshot)(ref val2)).IsDeactivated || ((ScrapItemSnapshot)(ref val2)).IsUsedUp || ((((ScrapItemSnapshot)(ref val2)).IsHeld || ((ScrapItemSnapshot)(ref val2)).IsHeldByEnemy || ((ScrapItemSnapshot)(ref val2)).IsPocketed) && !debug.ShowHeldItems))
						{
							num4++;
						}
						else
						{
							num5++;
						}
					}
					continue;
				}
				if (!usesVanillaScanNodes)
				{
					trackedScrapItem.RefreshValue(num10);
				}
				bool flag2 = presenter.IsActive(trackedScrapItem);
				if (preLayoutItems.Count < num8)
				{
					AddPreLayoutCandidate(trackedScrapItem, ((ScrapItemSnapshot)(ref val2)).DistanceSquaredToPlayer, flag2);
					if (preLayoutItems.Count == num8)
					{
						index = FindLowestPreLayoutPriorityIndex();
					}
					continue;
				}
				num6++;
				ScrapLabelPreCandidate val3 = new ScrapLabelPreCandidate(trackedScrapItem.RegistrationId, ((ScrapItemSnapshot)(ref val2)).DistanceSquaredToPlayer, trackedScrapItem.ScrapValue, flag2);
				ScrapLabelPreCandidate val4 = CreatePreLayoutCandidate(index);
				if (ScrapLabelPreCandidatePriority.IsHigherPriority(val3, val4))
				{
					ReplacePreLayoutCandidate(index, trackedScrapItem, ((ScrapItemSnapshot)(ref val2)).DistanceSquaredToPlayer, flag2);
					index = FindLowestPreLayoutPriorityIndex();
				}
			}
			for (int j = 0; j < preLayoutItems.Count; j++)
			{
				TrackedScrapItem trackedScrapItem2 = preLayoutItems[j];
				Vector3 labelAnchor = trackedScrapItem2.GetLabelAnchor(settings.HeightOffset);
				Vector3 val5 = playerCamera.WorldToScreenPoint(labelAnchor);
				if (val5.z <= 0f)
				{
					num5++;
					continue;
				}
				layoutItems.Add(trackedScrapItem2);
				layoutAnchors.Add(labelAnchor);
				layoutCandidates.Add(new ScrapLabelCandidate(trackedScrapItem2.RegistrationId, val5.x, val5.y, val5.z, trackedScrapItem2.ScrapValue, preLayoutWasVisible[j]));
			}
			layoutResolver.ResolveInto((IReadOnlyList<ScrapLabelCandidate>)layoutCandidates, settings.Visibility.MaxVisibleLabels, layoutPlacements);
			for (int k = 0; k < layoutPlacements.Count; k++)
			{
				ScrapLabelPlacement placement = layoutPlacements[k];
				if (!((ScrapLabelPlacement)(ref placement)).IsVisible)
				{
					num7++;
					continue;
				}
				Vector3 worldPosition = presenter.ResolvePlacedWorldPosition(playerCamera, layoutAnchors[k], placement);
				presenter.Show(layoutItems[k], worldPosition, playerCamera, settings);
				num++;
			}
			presenter.EndFrame();
			diagnostics.LogScanIfDue(debug, playerCamera, new ScrapDiagnosticCounters
			{
				Registered = registry.Count,
				Alive = num2,
				Candidates = layoutCandidates.Count,
				Shown = num,
				HiddenNoValue = num3,
				HiddenState = num4,
				HiddenDistance = num5,
				HiddenBudget = num6,
				HiddenOverlap = num7,
				PoolActive = presenter.ActiveCount,
				PoolIdle = presenter.IdleCount,
				TestLabel = presenter.DebugTestLabelVisible
			});
		}

		private void RefreshHighlightedVanillaScanItems(ModSettings settings, IReadOnlyList<TrackedScrapItem> sourceItems)
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			ScrapHighlightOptions highlight = settings.Highlight;
			if (!((ScrapHighlightOptions)(ref highlight)).Enabled)
			{
				highlightPresenter.HideAll();
				return;
			}
			highlightPresenter.BeginFrame();
			int count = sourceItems.Count;
			highlight = settings.Highlight;
			int num;
			if (count >= ((ScrapHighlightOptions)(ref highlight)).MaxHighlightedItems)
			{
				highlight = settings.Highlight;
				num = ((ScrapHighlightOptions)(ref highlight)).MaxHighlightedItems;
			}
			else
			{
				num = sourceItems.Count;
			}
			int num2 = num;
			for (int i = 0; i < num2; i++)
			{
				TrackedScrapItem trackedScrapItem = sourceItems[i];
				if (trackedScrapItem.IsAlive)
				{
					ScrapItemSnapshot val = CreateVanillaScanSnapshot(trackedScrapItem);
					if (highlightRules.ShouldShowVanillaScanned(val))
					{
						highlightPresenter.Show(trackedScrapItem);
					}
				}
			}
			highlightPresenter.EndFrame();
		}

		private static ScrapItemSnapshot CreateVanillaScanSnapshot(TrackedScrapItem tracked)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			return CreateItemSnapshot(tracked, tracked.HasUnknownValue ? 1 : tracked.ScrapValue, 0f);
		}

		private static ScrapItemSnapshot CreateItemSnapshot(TrackedScrapItem tracked, int scrapValue, float distanceSquaredToPlayer)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject item = tracked.Item;
			return new ScrapItemSnapshot(scrapValue, distanceSquaredToPlayer, item.isHeld, item.isHeldByEnemy, item.deactivated, item.isPocketed, item.itemUsedUp);
		}

		private void AddPreLayoutCandidate(TrackedScrapItem tracked, float distanceSquaredToPlayer, bool wasVisible)
		{
			preLayoutItems.Add(tracked);
			preLayoutDistanceSquares.Add(distanceSquaredToPlayer);
			preLayoutWasVisible.Add(wasVisible);
		}

		private static bool TryApplyScanNodeValue(ScanNodeProperties scanNode, TrackedScrapItem tracked, out bool valueChanged)
		{
			valueChanged = false;
			if (ScrapScanValueText.HasUnknownValue(scanNode.subText))
			{
				valueChanged = !tracked.HasUnknownValue;
				tracked.RefreshUnknownValue();
				return true;
			}
			if (!TryResolveKnownScanNodeValue(scanNode, tracked, out var scrapValue))
			{
				return false;
			}
			valueChanged = tracked.HasUnknownValue || tracked.ScrapValue != scrapValue;
			tracked.RefreshValue(scrapValue);
			return true;
		}

		private static bool TryResolveKnownScanNodeValue(ScanNodeProperties scanNode, TrackedScrapItem tracked, out int scrapValue)
		{
			scrapValue = 0;
			if (scanNode.scrapValue > 0)
			{
				scrapValue = scanNode.scrapValue;
				return true;
			}
			if (ScrapScanValueText.TryParseKnownValue(scanNode.subText, ref scrapValue))
			{
				return true;
			}
			if (tracked.Item.scrapValue > 0)
			{
				scrapValue = tracked.Item.scrapValue;
				return true;
			}
			scrapValue = scanNode.scrapValue;
			return true;
		}

		private bool VanillaScanItemsMatch()
		{
			if (visibleVanillaScanItems.Count != incomingVanillaScanItems.Count)
			{
				return false;
			}
			for (int i = 0; i < visibleVanillaScanItems.Count; i++)
			{
				if (visibleVanillaScanItems[i] != incomingVanillaScanItems[i])
				{
					return false;
				}
			}
			return true;
		}

		private void ReplacePreLayoutCandidate(int index, TrackedScrapItem tracked, float distanceSquaredToPlayer, bool wasVisible)
		{
			preLayoutItems[index] = tracked;
			preLayoutDistanceSquares[index] = distanceSquaredToPlayer;
			preLayoutWasVisible[index] = wasVisible;
		}

		private int FindLowestPreLayoutPriorityIndex()
		{
			//IL_0004: 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_0010: 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_0016: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			ScrapLabelPreCandidate val = CreatePreLayoutCandidate(num);
			for (int i = 1; i < preLayoutItems.Count; i++)
			{
				ScrapLabelPreCandidate val2 = CreatePreLayoutCandidate(i);
				if (ScrapLabelPreCandidatePriority.Compare(val2, val) > 0)
				{
					num = i;
					val = val2;
				}
			}
			return num;
		}

		private ScrapLabelPreCandidate CreatePreLayoutCandidate(int index)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			TrackedScrapItem trackedScrapItem = preLayoutItems[index];
			return new ScrapLabelPreCandidate(trackedScrapItem.RegistrationId, preLayoutDistanceSquares[index], trackedScrapItem.ScrapValue, preLayoutWasVisible[index]);
		}
	}
}
namespace Auuueser.ScanValue.Presentation
{
	internal static class ScrapHighlightMaterialFactory
	{
		public static Material Create(ScrapHighlightStyle style)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_005f: Expected O, but got Unknown
			Material val = new Material(Shader.Find("HDRP/Unlit") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default") ?? Shader.Find("Hidden/Internal-Colored"))
			{
				name = "ScanValue.ScanHighlight",
				hideFlags = (HideFlags)61,
				renderQueue = 3000
			};
			Apply(val, style);
			return val;
		}

		public static void Apply(Material material, ScrapHighlightStyle style)
		{
			//IL_0008: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			material.SetColor("_Color", style.Color);
			material.SetColor("_BaseColor", style.Color);
			material.SetColor("_UnlitColor", style.Color);
			material.SetInt("_Cull", 1);
			material.SetInt("_CullMode", 1);
			material.SetInt("_SrcBlend", 5);
			material.SetInt("_DstBlend", 10);
			material.SetInt("_ZWrite", 0);
			material.SetFloat("_SurfaceType", 1f);
			material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
		}
	}
	internal sealed class ScrapHighlightPresenter
	{
		private readonly Dictionary<TrackedScrapItem, ScrapHighlightView> activeViews = new Dictionary<TrackedScrapItem, ScrapHighlightView>(128);

		private readonly Dictionary<TrackedScrapItem, ScrapHighlightView> cachedViews = new Dictionary<TrackedScrapItem, ScrapHighlightView>(128);

		private readonly Dictionary<ScrapValueColorTier, Material> tierMaterials = new Dictionary<ScrapValueColorTier, Material>(6);

		private readonly List<TrackedScrapItem> staleItems = new List<TrackedScrapItem>(128);

		private ScrapHighlightStyle style = new ScrapHighlightStyle(Color32.op_Implicit(new Color32(byte.MaxValue, (byte)212, (byte)71, (byte)89)), 0.035f);

		private Material? fallbackMaterial;

		private ModSettings? currentSettings;

		private int frameId;

		public int CachedCount => cachedViews.Count;

		public void ApplyStyle(ModSettings settings)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			currentSettings = settings;
			style = ScrapHighlightStyle.FromSettings(settings);
			if (fallbackMaterial == null)
			{
				fallbackMaterial = ScrapHighlightMaterialFactory.Create(style);
			}
			ScrapHighlightMaterialFactory.Apply(fallbackMaterial, style);
			foreach (KeyValuePair<ScrapValueColorTier, Material> tierMaterial in tierMaterials)
			{
				ScrapHighlightMaterialFactory.Apply(tierMaterial.Value, CreateTierStyle(tierMaterial.Key, settings));
			}
			foreach (KeyValuePair<TrackedScrapItem, ScrapHighlightView> cachedView in cachedViews)
			{
				ScrapHighlightView value = cachedView.Value;
				value.ApplyStyle(style);
				value.ApplyMaterial(ResolveMaterial(cachedView.Key, settings));
			}
		}

		public void BeginFrame()
		{
			frameId++;
		}

		public void Show(TrackedScrapItem item)
		{
			Material sharedMaterial = ((currentSettings != null) ? ResolveMaterial(item, currentSettings) : GetOrCreateFallbackMaterial());
			if (!cachedViews.TryGetValue(item, out ScrapHighlightView value))
			{
				value = ScrapHighlightView.Create(item, sharedMaterial, style);
				cachedViews.Add(item, value);
			}
			else
			{
				value.ApplyMaterial(sharedMaterial);
			}
			activeViews[item] = value;
			value.FrameTouched = frameId;
			value.SetVisible(value: true);
		}

		public bool Prewarm(TrackedScrapItem item, ModSettings settings)
		{
			if (item == null || !item.IsAlive)
			{
				return false;
			}
			if (cachedViews.ContainsKey(item))
			{
				return false;
			}
			Material sharedMaterial = ResolveMaterial(item, settings);
			ScrapHighlightView value = ScrapHighlightView.Create(item, sharedMaterial, style);
			cachedViews.Add(item, value);
			return true;
		}

		public void EndFrame()
		{
			staleItems.Clear();
			foreach (KeyValuePair<TrackedScrapItem, ScrapHighlightView> activeView in activeViews)
			{
				if (activeView.Value.FrameTouched != frameId)
				{
					staleItems.Add(activeView.Key);
				}
			}
			for (int i = 0; i < staleItems.Count; i++)
			{
				TrackedScrapItem key = staleItems[i];
				if (activeViews.TryGetValue(key, out ScrapHighlightView value))
				{
					activeViews.Remove(key);
					value.SetVisible(value: false);
				}
			}
		}

		public void HideAll()
		{
			if (activeViews.Count == 0)
			{
				return;
			}
			foreach (ScrapHighlightView value in activeViews.Values)
			{
				value.SetVisible(value: false);
			}
			activeViews.Clear();
		}

		public void Hide(TrackedScrapItem item)
		{
			if (activeViews.TryGetValue(item, out ScrapHighlightView value))
			{
				activeViews.Remove(item);
				value.SetVisible(value: false);
			}
			else if (cachedViews.TryGetValue(item, out value))
			{
				value.SetVisible(value: false);
			}
		}

		public void ReapplyVisibilityState(TrackedScrapItem item)
		{
			if (cachedViews.TryGetValue(item, out ScrapHighlightView value))
			{
				value.ReapplyVisibilityState();
			}
		}

		private Material ResolveMaterial(TrackedScrapItem item, ModSettings settings)
		{
			//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_0019: 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_0020: 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)
			ScrapValueColorOptions valueColors = settings.ValueColors;
			if (!((ScrapValueColorOptions)(ref valueColors)).Enabled)
			{
				return GetOrCreateFallbackMaterial();
			}
			ScrapValueColorTier tier = ScrapValueVisualColorResolver.ResolveTier(item, settings);
			return GetOrCreateTierMaterial(tier, CreateTierStyle(tier, settings));
		}

		private Material GetOrCreateFallbackMaterial()
		{
			if (fallbackMaterial == null)
			{
				fallbackMaterial = ScrapHighlightMaterialFactory.Create(style);
			}
			return fallbackMaterial;
		}

		private Material GetOrCreateTierMaterial(ScrapValueColorTier tier, ScrapHighlightStyle tierStyle)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (tierMaterials.TryGetValue(tier, out Material value))
			{
				return value;
			}
			value = ScrapHighlightMaterialFactory.Create(tierStyle);
			tierMaterials.Add(tier, value);
			return value;
		}

		private static ScrapHighlightStyle CreateTierStyle(ScrapValueColorTier tier, ModSettings settings)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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)
			Color color = ScrapValueVisualColorResolver.ResolveHighlightColor(tier, settings);
			ScrapHighlightOptions highlight = settings.Highlight;
			return new ScrapHighlightStyle(color, ((ScrapHighlightOptions)(ref highlight)).Width);
		}
	}
	internal readonly struct ScrapHighlightStyle
	{
		public Color Color { get; }

		public float Width { get; }

		public ScrapHighlightStyle(Color color, float width)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Color = color;
			Width = width;
		}

		public static ScrapHighlightStyle FromSettings(ModSettings settings)
		{
			//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_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_001c: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			Color highlightColor = settings.HighlightColor;
			ScrapHighlightOptions highlight = settings.Highlight;
			highlightColor.a = ((ScrapHighlightOptions)(ref highlight)).Alpha;
			Color color = highlightColor;
			highlight = settings.Highlight;
			return new ScrapHighlightStyle(color, ((ScrapHighlightOptions)(ref highlight)).Width);
		}
	}
	internal sealed class ScrapHighlightView
	{
		private const string ProxyName = "ScanValue.ScanHighlightProxy";

		private readonly List<GameObject> proxyObjects = new List<GameObject>(8);

		private readonly List<Renderer> proxyRenderers = new List<Renderer>(8);

		private readonly List<Material[]> proxyMaterialSlots = new List<Material[]>(8);

		private readonly List<Transform> proxyTransforms = new List<Transform>(8);

		private Material? currentMaterial;

		private bool visible;

		public int FrameTouched { get; set; }

		private ScrapHighlightView()
		{
		}

		public static ScrapHighlightView Create(TrackedScrapItem item, Material sharedMaterial, ScrapHighlightStyle style)
		{
			ScrapHighlightView scrapHighlightView = new ScrapHighlightView();
			Renderer[] renderers = item.Renderers;
			foreach (Renderer val in renderers)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				MeshRenderer val2 = (MeshRenderer)(object)((val is MeshRenderer) ? val : null);
				if (val2 != null)
				{
					scrapHighlightView.AddMeshProxy(val2, sharedMaterial);
					continue;
				}
				SkinnedMeshRenderer val3 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null);
				if (val3 != null)
				{
					scrapHighlightView.AddSkinnedProxy(val3, sharedMaterial);
				}
			}
			scrapHighlightView.ApplyStyle(style);
			scrapHighlightView.ApplyMaterial(sharedMaterial);
			scrapHighlightView.SetVisible(value: false);
			return scrapHighlightView;
		}

		public void ApplyStyle(ScrapHighlightStyle style)
		{
			//IL_0000: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Vector3 localScale = Vector3.one * (1f + style.Width);
			for (int i = 0; i < proxyTransforms.Count; i++)
			{
				Transform val = proxyTransforms[i];
				if ((Object)(object)val != (Object)null)
				{
					val.localScale = localScale;
				}
			}
		}

		public void ApplyMaterial(Material sharedMaterial)
		{
			if ((Object)(object)currentMaterial == (Object)(object)sharedMaterial)
			{
				return;
			}
			currentMaterial = sharedMaterial;
			for (int i = 0; i < proxyRenderers.Count; i++)
			{
				Renderer val = proxyRenderers[i];
				if (!((Object)(object)val == (Object)null))
				{
					Material[] array = proxyMaterialSlots[i];
					for (int j = 0; j < array.Length; j++)
					{
						array[j] = sharedMaterial;
					}
					val.sharedMaterials = array;
				}
			}
		}

		public void SetVisible(bool value)
		{
			if (!(visible && value))
			{
				visible = value;
				ReapplyVisibilityState();
			}
		}

		public void ReapplyVisibilityState()
		{
			for (int i = 0; i < proxyRenderers.Count; i++)
			{
				GameObject val = proxyObjects[i];
				if ((Object)(object)val != (Object)null && val.activeSelf != visible)
				{
					val.SetActive(visible);
				}
				Renderer val2 = proxyRenderers[i];
				if ((Object)(object)val2 != (Object)null)
				{
					val2.enabled = visible;
				}
			}
		}

		private void AddMeshProxy(MeshRenderer source, Material sharedMaterial)
		{
			MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null))
			{
				GameObject obj = CreateProxyObject(((Component)source).transform);
				obj.AddComponent<MeshFilter>().sharedMesh = component.sharedMesh;
				MeshRenderer val = obj.AddComponent<MeshRenderer>();
				Material[] materialSlots = ConfigureRenderer((Renderer)(object)source, (Renderer)(object)val, sharedMaterial);
				AddProxy((Renderer)(object)val, materialSlots);
			}
		}

		private void AddSkinnedProxy(SkinnedMeshRenderer source, Material sharedMaterial)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)source.sharedMesh == (Object)null))
			{
				SkinnedMeshRenderer val = CreateProxyObject(((Component)source).transform).AddComponent<SkinnedMeshRenderer>();
				val.sharedMesh = source.sharedMesh;
				val.bones = source.bones;
				val.rootBone = source.rootBone;
				((Renderer)val).localBounds = ((Renderer)source).localBounds;
				val.updateWhenOffscreen = source.updateWhenOffscreen;
				Material[] materialSlots = ConfigureRenderer((Renderer)(object)source, (Renderer)(object)val, sharedMaterial);
				AddProxy((Renderer)(object)val, materialSlots);
			}
		}

		private static GameObject CreateProxyObject(Transform source)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			GameObject val = new GameObject("ScanValue.ScanHighlightProxy");
			val.transform.SetParent(source, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.layer = ((Component)source).gameObject.layer;
			val.tag = "DoNotSet";
			val.SetActive(false);
			return val;
		}

		private static Material[] ConfigureRenderer(Renderer source, Renderer target, Material sharedMaterial)
		{
			Material[] result = (target.sharedMaterials = CreateSharedMaterials(source.sharedMaterials.Length, sharedMaterial));
			target.shadowCastingMode = (ShadowCastingMode)0;
			target.receiveShadows = false;
			target.enabled = false;
			return result;
		}

		private void AddProxy(Renderer renderer, Material[] materialSlots)
		{
			proxyObjects.Add(((Component)renderer).gameObject);
			proxyRenderers.Add(renderer);
			proxyMaterialSlots.Add(materialSlots);
			proxyTransforms.Add(((Component)renderer).transform);
		}

		private static Material[] CreateSharedMaterials(int count, Material sharedMaterial)
		{
			Material[] array = (Material[])(object)new Material[(count <= 0) ? 1 : count];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = sharedMaterial;
			}
			return array;
		}
	}
	internal sealed class ScrapPriceBillboard : MonoBehaviour
	{
		private Camera? targetCamera;

		public void SetCamera(Camera? camera)
		{
			targetCamera = camera;
		}

		private void LateUpdate()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)targetCamera == (Object)null))
			{
				Vector3 forward = ((Component)targetCamera).transform.forward;
				Vector3 up = ((Component)targetCamera).transform.up;
				if (!(forward == Vector3.zero) && !(up == Vector3.zero))
				{
					((Component)this).transform.rotation = Quaternion.LookRotation(forward, up);
				}
			}
		}
	}
	internal sealed class ScrapPricePresenter
	{
		private readonly Transform parent;

		private readonly ScrapItemNameLocalizer nameLocalizer;

		private readonly Dictionary<TrackedScrapItem, ScrapPriceView> activeViews = new Dictionary<TrackedScrapItem, ScrapPriceView>(128);

		private readonly List<TrackedScrapItem> staleItems = new List<TrackedScrapItem>(128);

		private readonly Stack<ScrapPriceView> pool = new Stack<ScrapPriceView>(128);

		private ScrapPriceStyle style = new ScrapPriceStyle(0.18f, 3.5f, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)212, (byte)71, byte.MaxValue)), Color32.op_Implicit(new Color32((byte)16, (byte)16, (byte)16, byte.MaxValue)), 0.25f);

		private ScrapPriceView? debugTestLabel;

		private int frameId;

		public int ActiveCount => activeViews.Count;

		public int IdleCount => pool.Count;

		public bool DebugTestLabelVisible => debugTestLabel != null;

		public ScrapPricePresenter(Transform parent, ScrapItemNameLocalizer nameLocalizer)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			this.parent = parent;
			this.nameLocalizer = nameLocalizer;
		}

		public void ApplyStyle(ModSettings settings)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			style = ScrapPriceStyle.FromSettings(settings);
			foreach (KeyValuePair<TrackedScrapItem, ScrapPriceView> activeView in activeViews)
			{
				ScrapPriceView value = activeView.Value;
				value.ApplyStyle(style);
				value.ApplyValueColor(ScrapValueVisualColorResolver.ResolveLabelColor(activeView.Key, settings));
			}
			foreach (ScrapPriceView item in pool)
			{
				item.ApplyStyle(style);
				item.ApplyValueColor(style.LabelColor);
			}
			if (debugTestLabel != null)
			{
				debugTestLabel.ApplyStyle(style);
				debugTestLabel.ApplyValueColor(style.LabelColor);
			}
		}

		public void BeginFrame()
		{
			frameId++;
		}

		public bool IsActive(TrackedScrapItem item)
		{
			return activeViews.ContainsKey(item);
		}

		public void Show(TrackedScrapItem item, Vector3 worldPosition, Camera camera, ModSettings settings)
		{
			//IL_0034: 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)
			if (!activeViews.TryGetValue(item, out ScrapPriceView value))
			{
				value = Rent();
				activeViews.Add(item, value);
			}
			value.FrameTouched = frameId;
			value.ApplyValueColor(ScrapValueVisualColorResolver.ResolveLabelColor(item, settings));
			string itemName = nameLocalizer.ResolveDisplayName(item, settings);
			if (item.ValueTextOverride != null)
			{
				value.SetNameAndValue(itemName, item.ValueTextOverride);
			}
			else
			{
				value.SetNameAndValue(itemName, item.ScrapValue);
			}
			value.SetWorldPosition(worldPosition, camera);
			value.SetVisible(visible: true);
		}

		public void ShowDebugTestLabel(Camera camera)
		{
			//IL_001a: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (debugTestLabel == null)
			{
				debugTestLabel = Rent();
			}
			Vector3 worldPosition = ((Component)camera).transform.position + ((Component)camera).transform.forward * 2.25f - ((Component)camera).transform.up * 0.35f;
			debugTestLabel.FrameTouched = frameId;
			debugTestLabel.ApplyValueColor(style.LabelColor);
			debugTestLabel.SetText("$TEST");
			debugTestLabel.SetWorldPosition(worldPosition, camera);
			debugTestLabel.SetVisible(visible: true);
		}

		public void HideDebugTestLabel()
		{
			if (debugTestLabel != null)
			{
				Return(debugTestLabel);
				debugTestLabel = null;
			}
		}

		public Vector3 ResolvePlacedWorldPosition(Camera camera, Vector3 anchor, ScrapLabelPlacement placement)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = camera.WorldToScreenPoint(anchor);
			return camera.ScreenToWorldPoint(new Vector3(((ScrapLabelPlacement)(ref placement)).ScreenX, ((ScrapLabelPlacement)(ref placement)).ScreenY, val.z));
		}

		public void EndFrame()
		{
			staleItems.Clear();
			foreach (KeyValuePair<TrackedScrapItem, ScrapPriceView> activeView in activeViews)
			{
				if (activeView.Value.FrameTouched != frameId)
				{
					staleItems.Add(activeView.Key);
				}
			}
			for (int i = 0; i < staleItems.Count; i++)
			{
				TrackedScrapItem key = staleItems[i];
				ScrapPriceView view = activeViews[key];
				activeViews.Remove(key);
				Return(view);
			}
		}

		public void HideAll()
		{
			HideDebugTestLabel();
			HideScrapLabels();
		}

		public void HideScrapLabels()
		{
			if (activeViews.Count == 0)
			{
				return;
			}
			staleItems.Clear();
			foreach (TrackedScrapItem key2 in activeViews.Keys)
			{
				staleItems.Add(key2);
			}
			for (int i = 0; i < staleItems.Count; i++)
			{
				TrackedScrapItem key = staleItems[i];
				ScrapPriceView view = activeViews[key];
				activeViews.Remove(key);
				Return(view);
			}
		}

		public void Prewarm(int targetCount, int maxCreatedCount)
		{
			if (targetCount <= 0 || maxCreatedCount <= 0)
			{
				return;
			}
			for (int i = 0; i < maxCreatedCount; i++)
			{
				if (pool.Count >= targetCount)
				{
					break;
				}
				ScrapPriceView scrapPriceView = ScrapPriceView.Create(parent, style);
				scrapPriceView.SetVisible(visible: false);
				pool.Push(scrapPriceView);
			}
		}

		private ScrapPriceView Rent()
		{
			if (pool.Count > 0)
			{
				return pool.Pop();
			}
			return ScrapPriceView.Create(parent, style);
		}

		private void Return(ScrapPriceView view)
		{
			view.SetVisible(visible: false);
			pool.Push(view);
		}
	}
	internal sealed class ScrapPriceStyle
	{
		public float WorldScale { get; }

		public float FontSize { get; }

		public Color LabelColor { get; }

		public Color OutlineColor { get; }

		public float OutlineWidth { get; }

		public ScrapPriceStyle(float worldScale, float fontSize, Color labelColor, Color outlineColor, float outlineWidth)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			WorldScale = worldScale;
			FontSize = fontSize;
			LabelColor = labelColor;
			OutlineColor = outlineColor;
			OutlineWidth = outlineWidth;
		}

		public static ScrapPriceStyle FromSettings(ModSettings settings)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			return new ScrapPriceStyle(settings.WorldScale, settings.FontSize, settings.LabelColor, settings.OutlineColor, settings.OutlineWidth);
		}
	}
	internal sealed class ScrapPriceView
	{
		private const float PriceOnlyWidth = 240f;

		private const float PriceOnlyHeight = 72f;

		private const float NamedWidth = 300f;

		private const float NamedHeight = 112f;

		private const float WorldScaleMultiplier = 0.02f;

		private const float FontSizeMultiplier = 12f;

		private const float NameFontSizeMultiplier = 4.8f;

		private static readonly Vector3 ParkedWorldPosition = new Vector3(0f, -10000f, 0f);

		private static TMP_FontAsset? resolvedDefaultTextFont;

		private static TMP_FontAsset? resolvedChineseFallbackFont;

		private static bool defaultTextFontResolved;

		private static bool chineseFallbackFontResolved;

		private readonly GameObject gameObject;

		private readonly RectTransform root;

		private readonly RectTransform nameRect;

		private readonly RectTransform valueRect;

		private readonly TextMeshProUGUI nameText;

		private readonly TextMeshProUGUI valueText;

		private readonly TextMeshProUGUI anchorMarker;

		private readonly Canvas worldCanvas;

		private readonly ScrapPriceBillboard billboard;

		private Camera? lastAppliedCanvasCamera;

		private string? lastNameText;

		private string? lastValueText;

		private int lastValueNumber;

		private bool lastValueWasNumeric;

		private bool lastHasName;

		private bool layoutApplied;

		private Color lastValueColor;

		private bool valueColorApplied;

		private bool visible;

		private ScrapPriceStyle currentStyle;

		public int FrameTouched { get; set; }

		private ScrapPriceView(GameObject gameObject, RectTransform root, RectTransform nameRect, RectTransform valueRect, TextMeshProUGUI nameText, TextMeshProUGUI valueText, TextMeshProUGUI anchorMarker, Canvas worldCanvas, ScrapPriceBillboard billboard)
		{
			this.gameObject = gameObject;
			this.root = root;
			this.nameRect = nameRect;
			this.valueRect = valueRect;
			this.nameText = nameText;
			this.valueText = valueText;
			this.anchorMarker = anchorMarker;
			this.worldCanvas = worldCanvas;
			this.billboard = billboard;
		}

		public static ScrapPriceView Create(Transform parent, ScrapPriceStyle style)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0087: 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)
			//IL_00a4: Expected O, but got Unknown
			//IL_00a4: Expected O, but got Unknown
			//IL_00a4: Expected O, but got Unknown
			GameObject val = new GameObject("ScrapValueLabel");
			val.transform.SetParent(parent, false);
			ScrapPriceBillboard scrapPriceBillboard = val.AddComponent<ScrapPriceBillboard>();
			RectTransform parent2 = val.AddComponent<RectTransform>();
			Canvas val2 = val.AddComponent<Canvas>();
			val2.renderMode = (RenderMode)2;
			val2.overrideSorting = true;
			val2.sortingOrder = 600;
			val.AddComponent<CanvasScaler>();
			TextMeshProUGUI val3 = CreateText((Transform)(object)parent2, "NameText", useChineseFallback: true);
			TextMeshProUGUI val4 = CreateText((Transform)(object)parent2, "PriceText", useChineseFallback: false);
			TextMeshProUGUI val5 = CreateAnchorMarker((Transform)(object)parent2);
			SetLayerRecursively(val, ((Component)parent).gameObject.layer);
			ScrapPriceView scrapPriceView = new ScrapPriceView(val, parent2, (RectTransform)((TMP_Text)val3).transform, (RectTransform)((TMP_Text)val4).transform, val3, val4, val5, val2, scrapPriceBillboard);
			scrapPriceView.ApplyStyle(style);
			scrapPriceView.SetVisible(visible: false);
			return scrapPriceView;
		}

		private static TextMeshProUGUI CreateText(Transform parent, string objectName, bool useChineseFallback)
		{
			//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_0013: 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_0025: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(objectName);
			val.transform.SetParent(parent, false);
			RectTransform obj = val.AddComponent<RectTransform>();
			obj.anchorMin = Vector2.zero;
			obj.anchorMax = Vector2.one;
			obj.offsetMin = Vector2.zero;
			obj.offsetMax = Vector2.zero;
			val.AddComponent<CanvasRenderer>();
			TextMeshProUGUI obj2 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj2).alignment = (TextAlignmentOptions)514;
			((TMP_Text)obj2).enableWordWrapping = false;
			((TMP_Text)obj2).richText = false;
			((Graphic)obj2).raycastTarget = false;
			((TMP_Text)obj2).overflowMode = (TextOverflowModes)0;
			((TMP_Text)obj2).enableAutoSizing = true;
			((TMP_Text)obj2).fontStyle = (FontStyles)1;
			ApplyTextFont(obj2, useChineseFallback);
			return obj2;
		}

		private static TextMeshProUGUI CreateAnchorMarker(Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_0052: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("AnchorMarker");
			val.transform.SetParent(parent, false);
			RectTransform obj = val.AddComponent<RectTransform>();
			obj.anchorMin = new Vector2(0.5f, 0f);
			obj.anchorMax = new Vector2(0.5f, 0f);
			obj.sizeDelta = new Vector2(28f, 18f);
			obj.anchoredPosition = new Vector2(0f, -4f);
			val.AddComponent<CanvasRenderer>();
			TextMeshProUGUI obj2 = val.AddComponent<TextMeshProUGUI>();
			((Object)obj2).name = "AnchorMarker";
			((TMP_Text)obj2).alignment = (TextAlignmentOptions)514;
			((TMP_Text)obj2).enableWordWrapping = false;
			((TMP_Text)obj2).richText = false;
			((Graphic)obj2).raycastTarget = false;
			((TMP_Text)obj2).text = "v";
			ApplyTextFont(obj2, useChineseFallback: false);
			return obj2;
		}

		public void ApplyStyle(ScrapPriceStyle style)
		{
			//IL_000d: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			currentStyle = style;
			((Transform)root).localScale = Vector3.one * (style.WorldScale * 0.02f);
			float num = style.FontSize * 12f;
			((TMP_Text)valueText).fontSize = num;
			((TMP_Text)valueText).fontSizeMin = Mathf.Max(8f, num * 0.55f);
			((TMP_Text)valueText).fontSizeMax = num;
			((TMP_Text)valueText).outlineColor = Color32.op_Implicit(style.OutlineColor);
			((TMP_Text)valueText).outlineWidth = style.OutlineWidth;
			float num2 = style.FontSize * 4.8f;
			((TMP_Text)nameText).fontSize = num2;
			((TMP_Text)nameText).fontSizeMin = Mathf.Max(7f, num2 * 0.55f);
			((TMP_Text)nameText).fontSizeMax = num2;
			((TMP_Text)nameText).outlineColor = Color32.op_Implicit(style.OutlineColor);
			((TMP_Text)nameText).outlineWidth = style.OutlineWidth;
			((TMP_Text)anchorMarker).fontSize = style.FontSize * 5f;
			((TMP_Text)anchorMarker).outlineColor = Color32.op_Implicit(style.OutlineColor);
			((TMP_Text)anchorMarker).outlineWidth = style.OutlineWidth;
			ApplyValueColor(style.LabelColor, force: true);
			ApplyTextLayout(lastHasName);
		}

		public void ApplyValueColor(Color color)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ApplyValueColor(color, force: false);
		}

		private static void ApplyTextFont(TextMeshProUGUI text, bool useChineseFallback)
		{
			TMP_FontAsset val = (useChineseFallback ? (ResolveChineseFallbackFont() ?? ResolveDefaultTextFont()) : ResolveDefaultTextFont());
			if ((Object)(object)val != (Object)null)
			{
				((TMP_Text)text).font = val;
			}
		}

		private static TMP_FontAsset? ResolveDefaultTextFont()
		{
			if (defaultTextFontResolved)
			{
				return resolvedDefaultTextFont;
			}
			defaultTextFontResolved = true;
			resolvedDefaultTextFont = TMP_Settings.defaultFontAsset;
			if ((Object)(object)resolvedDefaultTextFont != (Object)null)
			{
				return resolvedDefaultTextFont;
			}
			Font builtinResource = Resources.GetBuiltinResource<Font>("Arial.ttf");
			if ((Object)(object)builtinResource != (Object)null)
			{
				resolvedDefaultTextFont = TMP_FontAsset.CreateFontAsset(builtinResource);
			}
			return resolvedDefaultTextFont;
		}

		private static TMP_FontAsset? ResolveChineseFallbackFont()
		{
			if (chineseFallbackFontResolved)
			{
				return resolvedChineseFallbackFont;
			}
			chineseFallbackFontResolved = true;
			List<TMP_FontAsset> fallbackFontAssets = TMP_Settings.fallbackFontAssets;
			if (fallbackFontAssets == null)
			{
				return null;
			}
			for (int i = 0; i < fallbackFontAssets.Count; i++)
			{
				TMP_FontAsset val = fallbackFontAssets[i];
				string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : string.Empty);
				if (text.IndexOf("V81TestChn", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("zh-cn", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("tmp-font", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("NotoSansSC", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("SourceHan", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Chinese", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					resolvedChineseFallbackFont = val;
					return resolvedChineseFallbackFont;
				}
			}
			return resolvedChineseFallbackFont;
		}

		public void SetValue(int value)
		{
			SetNameAndValue(null, value);
		}

		public void SetNameAndValue(string? itemName, int value)
		{
			bool flag = !string.IsNullOrWhiteSpace(itemName);
			ApplyTextLayout(flag);
			SetNameText(flag ? itemName : null);
			SetValueText(value);
		}

		public void SetNameAndValue(string? itemName, string value)
		{
			bool flag = !string.IsNullOrWhiteSpace(itemName);
			ApplyTextLayout(flag);
			SetNameText(flag ? itemName : null);
			lastValueWasNumeric = false;
			SetValueText(value);
		}

		public void SetText(string value)
		{
			ApplyTextLayout(hasName: false);
			SetNameText(null);
			lastValueWasNumeric = false;
			SetValueText(value);
		}

		public void SetWorldPosition(Vector3 worldPosition, Camera camera)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			((Transform)root).position = worldPosition;
			ApplyCanvasCamera(camera);
		}

		public void SetVisible(bool visible)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (this.visible != visible || !gameObject.activeSelf || (!visible && !(((Transform)root).position == ParkedWorldPosition)))
			{
				this.visible = visible;
				if (!gameObject.activeSelf)
				{
					gameObject.SetActive(true);
				}
				((Behaviour)billboard).enabled = visible;
				if (!visible)
				{
					billboard.SetCamera(null);
					((Transform)root).position = ParkedWorldPosition;
				}
			}
		}

		private void ApplyTextLayout(bool hasName)
		{
			//IL_004d: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			if (currentStyle != null && (!layoutApplied || lastHasName != hasName))
			{
				layoutApplied = true;
				lastHasName = hasName;
				root.sizeDelta = (hasName ? new Vector2(300f, 112f) : new Vector2(240f, 72f));
				((Component)nameText).gameObject.SetActive(hasName);
				if (hasName)
				{
					nameRect.anchorMin = new Vector2(0f, 0.56f);
					nameRect.anchorMax = new Vector2(1f, 1f);
					nameRect.offsetMin = Vector2.zero;
					nameRect.offsetMax = Vector2.zero;
					valueRect.anchorMin = new Vector2(0f, 0.04f);
					valueRect.anchorMax = new Vector2(1f, 0.7f);
				}
				else
				{
					valueRect.anchorMin = Vector2.zero;
					valueRect.anchorMax = Vector2.one;
				}
				valueRect.offsetMin = Vector2.zero;
				valueRect.offsetMax = Vector2.zero;
			}
		}

		private void SetNameText(string? value)
		{
			if (!(lastNameText == value))
			{
				lastNameText = value;
				((TMP_Text)nameText).text = value ?? string.Empty;
			}
		}

		private void SetValueText(int value)
		{
			if (!lastValueWasNumeric || lastValueNumber != value)
			{
				lastValueWasNumeric = true;
				lastValueNumber = value;
				SetValueText(ScrapPriceText.Format(value));
			}
		}

		private void SetValueText(string value)
		{
			if (!(lastValueText == value))
			{
				lastValueText = value;
				((TMP_Text)valueText).text = value;
			}
		}

		private void ApplyValueColor(Color color, bool force)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (force || !valueColorApplied || !(lastValueColor == color))
			{
				valueColorApplied = true;
				lastValueColor = color;
				((Graphic)valueText).color = color;
				((Graphic)nameText).color = color;
				((Graphic)anchorMarker).color = color;
			}
		}

		private void ApplyCanvasCamera(Camera camera)
		{
			billboard.SetCamera(camera);
			if (!((Object)(object)lastAppliedCanvasCamera == (Object)(object)camera) || !((Object)(object)worldCanvas.worldCamera == (Object)(object)camera))
			{
				worldCanvas.worldCamera = camera;
				lastAppliedCanvasCamera = camera;
			}
		}

		private static void SetLayerRecursively(GameObject target, int layer)
		{
			target.layer = layer;
			Transform transform = target.transform;
			for (int i = 0; i < transform.childCount; i++)
			{
				SetLayerRecursively(((Component)transform.GetChild(i)).gameObject, layer);
			}
		}
	}
	internal static class ScrapValueVisualColorResolver
	{
		public static Color ResolveLabelColor(TrackedScrapItem item, ModSettings settings)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0011: 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)
			Color result = ResolveBaseColor(item, settings, settings.LabelColor);
			result.a = settings.LabelColor.a;
			return result;
		}

		public static Color ResolveHighlightColor(TrackedScrapItem item, ModSettings settings)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Color result = ResolveBaseColor(item, settings, settings.HighlightColor);
			ScrapHighlightOptions highlight = settings.Highlight;
			result.a = ((ScrapHighlightOptions)(ref highlight)).Alpha;
			return result;
		}

		public static Color ResolveHighlightColor(ScrapValueColorTier tier, ModSettings settings)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Color result = ResolveBaseColor(tier, settings, settings.HighlightColor);
			ScrapHighlightOptions highlight = settings.Highlight;
			result.a = ((ScrapHighlightOptions)(ref highlight)).Alpha;
			return result;
		}

		public static ScrapValueColorTier ResolveTier(TrackedScrapItem item, ModSettings settings)
		{
			//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_0015: Unknown result type (might be due to invalid IL or missing references)
			ScrapValueColorOptions valueColors = settings.ValueColors;
			return ((ScrapValueColorOptions)(ref valueColors)).ResolveTier(item.HasUnknownValue, item.ScrapValue);
		}

		private static Color ResolveBaseColor(TrackedScrapItem item, ModSettings settings, Color fallback)
		{
			//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_0014: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			ScrapValueColorOptions valueColors = settings.ValueColors;
			if (!((ScrapValueColorOptions)(ref valueColors)).Enabled)
			{
				return fallback;
			}
			return ResolveBaseColor(ResolveTier(item, settings), settings, fallback);
		}

		private static Color ResolveBaseColor(ScrapValueColorTier tier, ModSettings settings, Color fallback)
		{
			//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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected I4, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			ScrapValueColorOptions valueColors = settings.ValueColors;
			if (!((ScrapValueColorOptions)(ref valueColors)).Enabled)
			{
				return fallback;
			}
			return (Color)((int)tier switch
			{
				0 => settings.UnknownValueColor, 
				1 => settings.LowValueColor, 
				2 => settings.MediumValueColor, 
				3 => settings.HighValueColor, 
				4 => settings.VeryHighValueColor, 
				5 => settings.JackpotValueColor, 
				_ => fallback, 
			});
		}
	}
}
namespace Auuueser.ScanValue.Localization
{
	internal static class ChineseProjectResourceLocator
	{
		public static IReadOnlyList<string> FindDictionaryFiles(ManualLogSource logger)
		{
			List<string> result = new List<string>(8);
			foreach (string item in FindChineseProjectPluginDirectories(logger))
			{
				AddIfActive(result, Path.Combine(item, "V81TestChn", "translations-clean", "zh-CN.runtime.json"));
				AddIfActive(result, Path.Combine(item, "translations-clean", "zh-CN.runtime.json"));
				AddCfgDirectory(result, Path.Combine(item, "V81TestChn", "translations-clean", "cfg", "zh-CN"));
				AddCfgDirectory(result, Path.Combine(item, "translations-clean", "cfg", "zh-CN"));
				AddCfgDirectory(result, Path.Combine(item, "V81TestChn", "translations-clean", "split", "cfg", "zh-CN"));
				AddCfgDirectory(result, Path.Combine(item, "translations-clean", "split", "cfg", "zh-CN"));
			}
			return result;
		}

		private static IEnumerable<string> FindChineseProjectPluginDirectories(ManualLogSource logger)
		{
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				PluginInfo value = pluginInfo.Value;
				if (((value != null) ? value.Metadata : null) != null && ChineseProjectDetection.IsChineseProjectPlugin(value.Metadata.GUID, value.Metadata.Name, value.Location))
				{
					string directoryName = Path.GetDirectoryName(value.Location);
					if (!string.IsNullOrEmpty(directoryName))
					{
						yield return directoryName;
					}
				}
			}
			foreach (string item in FindChineseProjectManifestPaths(logger))
			{
				string directoryName2 = Path.GetDirectoryName(item);
				if (!string.IsNullOrEmpty(directoryName2))
				{
					yield return directoryName2;
				}
			}
		}

		private static IEnumerable<string> FindChineseProjectManifestPaths(ManualLogSource logger)
		{
			if (!Directory.Exists(Paths.PluginPath))
			{
				yield break;
			}
			IEnumerable<string> enumerable;
			try
			{
				enumerable = Directory.EnumerateFiles(Paths.PluginPath, "manifest.json", SearchOption.AllDirectories);
			}
			catch (Exception ex)
			{
				logger.LogWarning((object)("Could not inspect plugin manifests for item-name dictionaries: " + ex.Message));
				yield break;
			}
			foreach (string item in enumerable)
			{
				string text;
				try
				{
					text = File.ReadAllText(item);
				}
				catch
				{
					continue;
				}
				if (ChineseProjectDetection.ContainsChineseProjectManifestText(text))
				{
					yield return item;
				}
			}
		}

		private static void AddCfgDirectory(List<string> result, string directory)
		{
			if (!Directory.Exists(directory))
			{
				return;
			}
			foreach (string item in Directory.EnumerateFiles(directory, "*.cfg", SearchOption.TopDirectoryOnly))
			{
				AddIfActive(result, item);
			}
		}

		private static void AddIfActive(List<string> result, string path)
		{
			if (File.Exists(path) && ScrapNameDictionaryFiles.IsActiveDictionaryFile(path) && !result.Contains(path))
			{
				result.Add(path);
			}
		}
	}
	internal sealed class ScrapItemNameLocalizer
	{
		private readonly ManualLogSource logger;

		private readonly ScrapNameTranslationMap translations = new ScrapNameTranslationMap();

		private readonly bool chineseProjectDetected;

		public bool HasChineseDictionary => translations.HasEntries;

		private ScrapItemNameLocalizer(ManualLogSource logger, bool chineseProjectDetected)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			this.logger = logger;
			this.chineseProjectDetected = chineseProjectDetected;
		}

		public static ScrapItemNameLocalizer Load(ManualLogSource logger)
		{
			IReadOnlyList<string> readOnlyList = ChineseProjectResourceLocator.FindDictionaryFiles(logger);
			ScrapItemNameLocalizer scrapItemNameLocalizer = new ScrapItemNameLocalizer(logger, readOnlyList.Count > 0);
			for (int i = 0; i < readOnlyList.Count; i++)
			{
				scrapItemNameLocalizer.LoadFile(readOnlyList[i]);
			}
			if (scrapItemNameLocalizer.translations.HasEntries)
			{
				logger.LogInfo((object)$"ScanValue loaded {scrapItemNameLocalizer.translations.Count} item-name translations from {readOnlyList.Count} active LC Chinese Project resource(s).");
			}
			return scrapItemNameLocalizer;
		}

		public ScrapItemResolvedNames ResolveNames(string currentItemName)
		{
			if (string.IsNullOrWhiteSpace(currentItemName))
			{
				return new ScrapItemResolvedNames(string.Empty, string.Empty);
			}
			string text = translations.ToEnglish(currentItemName);
			string text2 = translations.ToChinese(text);
			if (string.Equals(text2, text, StringComparison.Ordinal))
			{
				text2 = translations.ToChinese(currentItemName);
			}
			return new ScrapItemResolvedNames(text, text2);
		}

		public string? ResolveDisplayName(TrackedScrapItem item, ModSettings settings)
		{
			//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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			ScrapItemNameOptions itemNames = settings.ItemNames;
			if (!((ScrapItemNameOptions)(ref itemNames)).ShowItemNames)
			{
				return null;
			}
			itemNames = settings.ItemNames;
			ScrapItemNameLanguage language = ((ScrapItemNameOptions)(ref itemNames)).Language;
			if ((int)language != 1)
			{
				if ((int)language == 2)
				{
					return NonEmptyOrFallback(item.EnglishName, item.ChineseName);
				}
				return ShouldUseChinese() ? NonEmptyOrFallback(item.ChineseName, item.EnglishName) : NonEmptyOrFallback(item.EnglishName, item.ChineseName);
			}
			return NonEmptyOrFallback(item.ChineseName, item.EnglishName);
		}

		private bool ShouldUseChinese()
		{
			if (chineseProjectDetected)
			{
				return translations.HasEntries;
			}
			return false;
		}

		private void LoadFile(string path)
		{
			try
			{
				string text = File.ReadAllText(path);
				if (string.Equals(Path.GetFileName(path), "zh-CN.runtime.json", StringComparison.OrdinalIgnoreCase))
				{
					ScrapNameDictionaryParser.AddRuntimeJson(translations, text);
				}
				else
				{
					ScrapNameDictionaryParser.AddCfg(translations, text);
				}
			}
			catch (Exception ex)
			{
				logger.LogWarning((object)("ScanValue could not load item-name dictionary '" + path + "': " + ex.Message));
			}
		}

		private static string? NonEmptyOrFallback(string primary, string fallback)
		{
			if (!string.IsNullOrWhiteSpace(primary))
			{
				return primary;
			}
			if (!string.IsNullOrWhiteSpace(fallback))
			{
				return fallback;
			}
			return null;
		}
	}
	internal readonly struct ScrapItemResolvedNames
	{
		public string EnglishName { get; }

		public string ChineseName { get; }

		public ScrapItemResolvedNames(string englishName, string chineseName)
		{
			EnglishName = englishName;
			ChineseName = chineseName;
		}
	}
}
namespace Auuueser.ScanValue.Game
{
	internal sealed class LocalPlayerProvider
	{
		public bool TryGet(out Vector3 playerPosition, out Camera playerCamera, out string failureReason)
		{
			//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_003f: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			playerPosition = Vector3.zero;
			playerCamera = null;
			failureReason = string.Empty;
			PlayerControllerB val = ResolveLocalPlayer();
			if ((Object)(object)val == (Object)null)
			{
				failureReason = "No local player";
				return false;
			}
			StartOfRound instance = StartOfRound.Instance;
			if (TryUseCamera(val.gameplayCamera, ((Component)val).transform.position, out playerPosition, out playerCamera))
			{
				return true;
			}
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.activeCamera != (Object)null && TryUseCamera(instance.activeCamera, ((Component)instance.activeCamera).transform.position, out playerPosition, out playerCamera))
			{
				return true;
			}
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.spectateCamera != (Object)null && TryUseCamera(instance.spectateCamera, ((Component)instance.spectateCamera).transform.position, out playerPosition, out playerCamera))
			{
				return true;
			}
			failureReason = "No usable camera";
			return false;
		}

		private static PlayerControllerB? ResolveLocalPlayer()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.localPlayerController != (Object)null)
			{
				return instance.localPlayerController;
			}
			HUDManager instance2 = HUDManager.Instance;
			if ((Object)(object)instance2 != (Object)null && (Object)(object)instance2.localPlayer != (Object)null)
			{
				return instance2.localPlayer;
			}
			GameNetworkManager instance3 = GameNetworkManager.Instance;
			if (!((Object)(object)instance3 != (Object)null))
			{
				return null;
			}
			return instance3.localPlayerController;
		}

		private static bool TryUseCamera(Camera? camera, Vector3 distanceCenter, out Vector3 playerPosition, out Camera playerCamera)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)camera != (Object)null && ((Behaviour)camera).isActiveAndEnabled)
			{
				playerPosition = distanceCenter;
				playerCamera = camera;
				return true;
			}
			playerPosition = Vector3.zero;
			playerCamera = null;
			return false;
		}
	}
	internal static class ScrapObjectHooks
	{
		private static ScrapObjectRegistry? registry;

		private static ManualLogSource? logger;

		private static Action<GrabbableObject>? meshVisibilityReapplier;

		public static void Initialize(ScrapObjectRegistry activeRegistry, ManualLogSource activeLogger, Action<GrabbableObject> activeMeshVisibilityReapplier)
		{
			registry = activeRegistry;
			logger = activeLogger;
			meshVisibilityReapplier = activeMeshVisibilityReapplier;
		}

		public static void Clear(ScrapObjectRegistry activeRegistry)
		{
			if (registry == activeRegistry)
			{
				registry = null;
				logger = null;
				meshVisibilityReapplier = null;
			}
		}

		public static void AfterGrabbableStart(GrabbableObject __instance)
		{
			registry?.Register(__instance);
		}

		public static void BeforeGrabbableDestroy(GrabbableObject __instance)
		{
			registry?.Unregister(__instance);
		}

		public static void AfterSetScrapValue(GrabbableObject __instance)
		{
			registry?.RefreshValue(__instance);
		}

		public static void AfterDestroyObjectInHand(GrabbableObject __instance)
		{
			registry?.Unregister(__instance);
		}

		public static void AfterEnableItemMeshes(GrabbableObject __instance)
		{
			meshVisibilityReapplier?.Invoke(__instance);
		}

		public static void LogPatchFailure(string methodName)
		{
			ManualLogSource? obj = logger;
			if (obj != null)
			{
				obj.LogWarning((object)("Could not patch GrabbableObject." + methodName + "; scrap value labels may miss late-spawned items."));
			}
		}
	}
	internal sealed class ScrapObjectMarker : MonoBehaviour
	{
		public ScrapObjectRegistry? Registry { get; private set; }

		public TrackedScrapItem? TrackedItem { get; private set; }

		public void Initialize(ScrapObjectRegistry registry, TrackedScrapItem trackedItem)
		{
			Registry = registry;
			TrackedItem = trackedItem;
		}

		public void ClearRegistration()
		{
			Registry = null;
			TrackedItem = null;
		}

		private void OnDestroy()
		{
			Registry?.UnregisterMarker(this);
		}
	}
	internal sealed class ScrapObjectPatcher : IDisposable
	{
		private readonly Harmony harmony;

		private readonly ScrapObjectRegistry registry;

		private readonly ManualLogSource logger;

		private int patchedCount;

		private bool disposed;

		public ScrapObjectPatcher(ScrapObjectRegistry registry, ManualLogSource logger, Action<GrabbableObject> meshVisibilityReapplier)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			this.registry = registry;
			this.logger = logger;
			harmony = new Harmony("com.auuueser.lethalcompany.scanvalue");
			ScrapObjectHooks.Initialize(registry, logger, meshVisibilityReapplier);
			Patch("Start", null, "AfterGrabbableStart");
			Patch("OnDestroy", "BeforeGrabbableDestroy");
			Patch("SetScrapValue", null, "AfterSetScrapValue");
			Patch("DestroyObjectInHand", null, "AfterDestroyObjectInHand");
			Patch("EnableItemMeshes", null, "AfterEnableItemMeshes");
			this.logger.LogInfo((object)$"ScanValue patched {patchedCount} GrabbableObject methods.");
		}

		public void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				harmony.UnpatchSelf();
				ScrapObjectHooks.Clear(registry);
			}
		}

		private void Patch(string originalName, string? prefixName = null, string? postfixName = null)
		{
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(GrabbableObject), originalName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				ScrapObjectHooks.LogPatchFailure(originalName);
				return;
			}
			HarmonyMethod val = CreateHarmonyMethod(prefixName);
			HarmonyMethod val2 = CreateHarmonyMethod(postfixName);
			harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patchedCount++;
		}

		private static HarmonyMethod? CreateHarmonyMethod(string? methodName)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (methodName == null)
			{
				return null;
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ScrapObjectHooks), methodName, (Type[])null, (Type[])null);
			if (!(methodInfo == null))
			{
				return new HarmonyMethod(methodInfo);
			}
			return null;
		}
	}
	internal sealed class ScrapObjectRegistry
	{
		private readonly ManualLogSource logger;

		private readonly ScrapItemNameLocalizer nameLocalizer;

		private readonly List<TrackedScrapItem> items = new List<TrackedScrapItem>(256);

		private readonly Dictionary<ScanNodeProperties, TrackedScrapItem> scanNodeLookup = new Dictionary<ScanNodeProperties, TrackedScrapItem>(256);

		private bool debugRegistrations;

		private bool debugTrackZeroValueItems;

		private int nextRegistrationId;

		public int Count => items.Count;

		public TrackedScrapItem this[int index] => items[index];

		public ScrapObjectRegistry(ManualLogSource logger, ScrapItemNameLocalizer nameLocalizer)
		{
			this.logger = logger;
			this.nameLocalizer = nameLocalizer;
		}

		public void SetDebugOptions(bool logRegistrations, bool trackZeroValueItems)
		{
			debugRegistrations = logRegistrations;
			debugTrackZeroValueItems = trackZeroValueItems;
		}

		public void Register(GrabbableObject item)
		{
			if (!ShouldTrack(item))
			{
				return;
			}
			ScrapObjectMarker component = ((Component)item).gameObject.GetComponent<ScrapObjectMarker>();
			if ((Object)(object)component != (Object)null && component.Registry == this && component.TrackedItem != null)
			{
				component.TrackedItem.RefreshValue(item.scrapValue);
				UpdateScanNode(component.TrackedItem, FindScanNode(item));
				component.TrackedItem.RefreshNames(nameLocalizer.ResolveNames(GetItemName(item)));
				return;
			}
			component = ((Component)item).gameObject.AddComponent<ScrapObjectMarker>();
			ScanNodeProperties scanNode = FindScanNode(item);
			TrackedScrapItem trackedScrapItem = new TrackedScrapItem(item, ((Component)item).transform, item.scrapValue, scanNode, FindRenderers(item), component, items.Count, nextRegistrationId++, nameLocalizer.ResolveNames(GetItemName(item)));
			component.Initialize(this, trackedScrapItem);
			items.Add(trackedScrapItem);
			AddScanNodeLookup(trackedScrapItem);
			if (debugRegistrations)
			{
				logger.LogInfo((object)$"ScanValue registered '{item.itemProperties.itemName}' value={item.scrapValue} count={items.Count}.");
			}
		}

		public void RefreshValue(GrabbableObject item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return;
			}
			ScrapObjectMarker component = ((Component)item).gameObject.GetComponent<ScrapObjectMarker>();
			if ((Object)(object)component != (Object)null && component.Registry == this && component.TrackedItem != null)
			{
				if (!ShouldTrack(item))
				{
					UnregisterMarker(component);
					return;
				}
				component.TrackedItem.RefreshValue(item.scrapValue);
				UpdateScanNode(component.TrackedItem, FindScanNode(item));
				component.TrackedItem.RefreshNames(nameLocalizer.ResolveNames(GetItemName(item)));
			}
			else
			{
				Register(item);
			}
		}

		public void Unregister(GrabbableObject item)
		{
			if (!((Object)(object)item == (Object)null))
			{
				ScrapObjectMarker component = ((Component)item).gameObject.GetComponent<ScrapObjectMarker>();
				if ((Object)(object)component != (Object)null)
				{
					UnregisterMarker(component);
				}
			}
		}

		public void UnregisterMarker(ScrapObjectMarker marker)
		{
			if (marker.Registry == this && marker.TrackedItem != null)
			{
				RemoveAt(marker.TrackedItem.Index);
				marker.ClearRegistration();
			}
		}

		public void Clear()
		{
			for (int num = items.Count - 1; num >= 0; num--)
			{
				items[num].Marker.ClearRegistration();
			}
			items.Clear();
			scanNodeLookup.Clear();
		}

		public bool TryGetByScanNode(ScanNodeProperties? scanNode, out TrackedScrapItem tracked)
		{
			if ((Object)(object)scanNode != (Object)null && scanNodeLookup.TryGetValue(scanNode, out tracked))
			{
				return true;
			}
			tracked = null;
			return false;
		}

		public bool TryGet(GrabbableObject item, out TrackedScrapItem tracked)
		{
			if ((Object)(object)item != (Object)null)
			{
				ScrapObjectMarker component = ((Component)item).gameObject.GetComponent<ScrapObjectMarker>();
				if ((Object)(object)component != (Object)null && component.Registry == this && component.TrackedItem != null)
				{
					tracked = component.TrackedItem;
					return true;
				}
			}
			tracked = null;
			return false;
		}

		private bool ShouldTrack(GrabbableObject item)
		{
			if ((Object)(object)item == (Object)null || (Object)(object)item.itemProperties == (Object)null)
			{
				return false;
			}
			if (!item.itemProperties.isScrap && item.scrapValue <= 0)
			{
				return debugTrackZeroValueItems;
			}
			return true;
		}

		private static string GetItemName(GrabbableObject item)
		{
			string text = (((Object)(object)item.itemProperties != (Object)null) ? item.itemProperties.itemName : null);
			if (!string.IsNullOrWhiteSpace(tex