Decompiled source of HaulOfFame v1.0.2

plugins\HaulOfFame.dll

Decompiled 10 hours 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 System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using HaulOfFame.Config;
using HaulOfFame.Core;
using HaulOfFame.Network;
using HaulOfFame.UI;
using HaulOfFame.Utils;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
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("HaulOfFame")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("HaulOfFame")]
[assembly: AssemblyTitle("HaulOfFame")]
[assembly: AssemblyVersion("1.0.2.0")]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace HaulOfFame
{
	[BepInPlugin("com.juanma.hauloffame", "HaulOfFame", "1.0.2")]
	[BepInProcess("REPO.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.juanma.hauloffame";

		public const string PluginName = "HaulOfFame";

		public const string PluginVersion = "1.0.2";

		private static Plugin? _activeInstance;

		private ModConfig? _modConfig;

		private GameBindings? _bindings;

		private HaulController? _controller;

		private Harmony? _harmony;

		private void Awake()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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_0128: Expected O, but got Unknown
			Scene activeScene = SceneManager.GetActiveScene();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[HaulOfFame] Loaded v1.0.2");
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}/Lifecycle] Awake: unity={1}, gameVersion={2}, scene={3}[{4}], config={5}", "HaulOfFame", Application.unityVersion, Application.version, ((Scene)(ref activeScene)).name, ((Scene)(ref activeScene)).buildIndex, ((BaseUnityPlugin)this).Config.ConfigFilePath));
			_modConfig = new ModConfig(((BaseUnityPlugin)this).Config);
			_bindings = new GameBindings(((BaseUnityPlugin)this).Logger);
			if (_bindings.Resolve())
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[HaulOfFame/Bindings] Required game bindings resolved.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[HaulOfFame/Bindings] One or more inspected fields are unavailable; affected captures will be skipped safely.");
			}
			try
			{
				_controller = new HaulController(_modConfig, _bindings, ((BaseUnityPlugin)this).Logger);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[HaulOfFame/Lifecycle] Initialization failed safely: " + ex.GetType().Name + ": " + ex.Message));
				return;
			}
			_activeInstance = this;
			_harmony = new Harmony("com.juanma.hauloffame");
			int num = 0;
			num += (InstallPatch(typeof(ExtractionPoint), "SpawnExtractingVisuals", "ValuableExtractingPrefix", prefix: true) ? 1 : 0);
			num += (InstallPatch(typeof(RoundDirector), "ExtractionCompleted", "ExtractionCompletedPostfix", prefix: false) ? 1 : 0);
			num += (InstallPatch(typeof(ItemValuableBox), "StartAbsorbLocal", "ValuableStoredPrefix", prefix: true) ? 1 : 0);
			num += (InstallPatch(typeof(ItemValuableBox), "OnExtracted", "ValuableBoxExtractedPrefix", prefix: true) ? 1 : 0);
			MethodInfo methodInfo = AccessTools.Method(typeof(Plugin), "GameUpdatePostfix", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				num += (InstallUpdateHook(typeof(GameDirector), methodInfo) ? 1 : 0);
				num += (InstallUpdateHook(typeof(RunManager), methodInfo) ? 1 : 0);
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}/Lifecycle] Installed {1}/6 hooks. Ready to record extracted valuables.", "HaulOfFame", num));
		}

		private void Update()
		{
			_controller?.Tick(Time.unscaledDeltaTime);
		}

		private static void GameUpdatePostfix()
		{
			_activeInstance?._controller?.Tick(Time.unscaledDeltaTime);
		}

		private static void ValuableExtractingPrefix(ExtractionPoint __instance, PhysGrabObject __0)
		{
			_activeInstance?._controller?.OnValuableExtracting(__instance, __0);
		}

		private static void ExtractionCompletedPostfix(RoundDirector __instance)
		{
			_activeInstance?._controller?.OnExtractionCompleted(__instance);
		}

		private static void ValuableStoredPrefix(ItemValuableBox __instance, PhysGrabObject __0)
		{
			_activeInstance?._controller?.OnValuableStored(__instance, __0);
		}

		private static void ValuableBoxExtractedPrefix(ItemValuableBox __instance)
		{
			_activeInstance?._controller?.OnValuableBoxExtracted(__instance);
		}

		private bool InstallPatch(Type gameType, string methodName, string patchName, bool prefix)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(gameType, methodName, (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), patchName, (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null || _harmony == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("[HaulOfFame/Hooks] Could not patch " + gameType.Name + "." + methodName + "."));
				return false;
			}
			if (prefix)
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[HaulOfFame/Hooks] Patched " + gameType.Name + "." + methodName + " (" + (prefix ? "prefix" : "postfix") + ")."));
			return true;
		}

		private bool InstallUpdateHook(Type gameType, MethodInfo postfix)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(gameType, "Update", (Type[])null, (Type[])null);
			if (methodInfo == null || _harmony == null)
			{
				return false;
			}
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			return true;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("[{0}/Scene] Loaded: {1}[{2}], mode={3}, frame={4}.", "HaulOfFame", ((Scene)(ref scene)).name, ((Scene)(ref scene)).buildIndex, mode, Time.frameCount));
			_controller?.HandleSceneChanged(scene);
		}

		private void OnActiveSceneChanged(Scene previous, Scene current)
		{
			ModConfig? modConfig = _modConfig;
			if (modConfig != null && modConfig.DebugLogging.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("[HaulOfFame/Scene] Active scene: " + ((Scene)(ref previous)).name + " -> " + ((Scene)(ref current)).name + "."));
			}
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[HaulOfFame/Lifecycle] Shutdown started.");
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SceneManager.activeSceneChanged -= OnActiveSceneChanged;
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)_activeInstance == (Object)(object)this)
			{
				_activeInstance = null;
			}
			_controller?.Dispose();
			_modConfig?.Dispose();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"[HaulOfFame/Lifecycle] Shutdown complete.");
		}
	}
}
namespace HaulOfFame.Utils
{
	internal static class TextureUtils
	{
		public static Sprite CreateRoundedRectSprite(string name, int width, int height, int radius, int borderThickness = 0)
		{
			//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_001a: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(width, height, (TextureFormat)4, false)
			{
				name = name + "_Texture",
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
			Color32[] array = (Color32[])(object)new Color32[width * height];
			for (int i = 0; i < height; i++)
			{
				for (int j = 0; j < width; j++)
				{
					bool flag = InsideRoundedRect((float)j + 0.5f, (float)i + 0.5f, width, height, radius, 0);
					bool flag2 = borderThickness > 0 && InsideRoundedRect((float)j + 0.5f, (float)i + 0.5f, width, height, Mathf.Max(0, radius - borderThickness), borderThickness);
					array[i * width + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)((flag && !flag2) ? byte.MaxValue : 0));
				}
			}
			val.SetPixels32(array);
			val.Apply(false, true);
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)width, (float)height), new Vector2(0.5f, 0.5f), 100f);
			((Object)obj).name = name;
			((Object)obj).hideFlags = (HideFlags)61;
			return obj;
		}

		private static bool InsideRoundedRect(float x, float y, int width, int height, int radius, int inset)
		{
			int num = width - inset;
			int num2 = height - inset;
			if (x < (float)inset || x > (float)num || y < (float)inset || y > (float)num2)
			{
				return false;
			}
			if (radius <= 0)
			{
				return true;
			}
			float num3 = Mathf.Clamp(x, (float)(inset + radius), (float)(num - radius));
			float num4 = Mathf.Clamp(y, (float)(inset + radius), (float)(num2 - radius));
			float num5 = x - num3;
			float num6 = y - num4;
			return num5 * num5 + num6 * num6 <= (float)(radius * radius);
		}
	}
}
namespace HaulOfFame.UI
{
	public sealed class AnnouncementHud : IDisposable
	{
		private readonly ModConfig _config;

		private readonly GameObject _root;

		private readonly RectTransform _panel;

		private readonly CanvasGroup _canvasGroup;

		private readonly Image _panelImage;

		private readonly Image _accentImage;

		private readonly Text _title;

		private readonly Text _name;

		private readonly Text _details;

		private readonly Sprite _panelSprite;

		private readonly Font _font;

		private readonly bool _ownsFont;

		private readonly AudioClip _sound;

		private readonly AudioSource _audioSource;

		private float _elapsed;

		private float _duration;

		private bool _visible;

		public AnnouncementHud(ModConfig config)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: 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_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_036a: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			_config = config;
			_font = Font.CreateDynamicFontFromOSFont(new string[4] { "Bahnschrift SemiCondensed", "Arial Narrow", "Segoe UI Semibold", "Arial" }, 20);
			if ((Object)(object)_font != (Object)null)
			{
				_ownsFont = true;
			}
			else
			{
				_font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			}
			_panelSprite = TextureUtils.CreateRoundedRectSprite("HaulOfFame_BannerPanel", 300, 64, 6);
			_sound = CreateSound();
			_root = new GameObject("HaulOfFame_Announcement")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)(object)_root);
			_audioSource = _root.AddComponent<AudioSource>();
			_audioSource.playOnAwake = false;
			_audioSource.loop = false;
			_audioSource.spatialBlend = 0f;
			_audioSource.ignoreListenerPause = true;
			Canvas obj = _root.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 25000;
			CanvasScaler obj2 = _root.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)1;
			obj2.referenceResolution = new Vector2(1920f, 1080f);
			obj2.screenMatchMode = (ScreenMatchMode)0;
			obj2.matchWidthOrHeight = 0.5f;
			GameObject val = new GameObject("Panel", new Type[4]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(CanvasGroup)
			});
			val.transform.SetParent(_root.transform, false);
			_panel = val.GetComponent<RectTransform>();
			_panel.anchorMin = new Vector2(0.5f, 1f);
			_panel.anchorMax = new Vector2(0.5f, 1f);
			_panel.pivot = new Vector2(0.5f, 1f);
			_panel.anchoredPosition = new Vector2(0f, -62f);
			_panel.sizeDelta = new Vector2(650f, 126f);
			_panelImage = val.GetComponent<Image>();
			_panelImage.sprite = _panelSprite;
			_panelImage.type = (Type)1;
			((Graphic)_panelImage).raycastTarget = false;
			_canvasGroup = val.GetComponent<CanvasGroup>();
			_canvasGroup.blocksRaycasts = false;
			_canvasGroup.interactable = false;
			_accentImage = CreateImage("Accent", (Transform)(object)_panel, new Vector2(0f, 0f), new Vector2(7f, 110f));
			RectTransform rectTransform = ((Graphic)_accentImage).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 0.5f);
			rectTransform.anchorMax = new Vector2(0f, 0.5f);
			rectTransform.pivot = new Vector2(0f, 0.5f);
			rectTransform.anchoredPosition = new Vector2(8f, 0f);
			_title = CreateText("Title", (Transform)(object)_panel, 18, (FontStyle)1, (TextAnchor)3);
			SetRect(((Graphic)_title).rectTransform, new Vector2(26f, -12f), new Vector2(598f, 24f), new Vector2(0f, 1f));
			_name = CreateText("Name", (Transform)(object)_panel, 29, (FontStyle)1, (TextAnchor)3);
			SetRect(((Graphic)_name).rectTransform, new Vector2(26f, -39f), new Vector2(598f, 38f), new Vector2(0f, 1f));
			_details = CreateText("Details", (Transform)(object)_panel, 17, (FontStyle)0, (TextAnchor)3);
			SetRect(((Graphic)_details).rectTransform, new Vector2(26f, -82f), new Vector2(598f, 28f), new Vector2(0f, 1f));
			ApplyConfig();
			_root.SetActive(false);
		}

		public void Show(string title, string name, string details)
		{
			if (_config.Enabled.Value && _config.ShowAnnouncement.Value)
			{
				_title.text = title;
				_name.text = name;
				_details.text = details;
				_elapsed = 0f;
				_duration = Mathf.Clamp(_config.AnnouncementDuration.Value, 1f, 20f);
				_visible = true;
				_root.SetActive(true);
				if (_config.SoundEnabled.Value)
				{
					_audioSource.PlayOneShot(_sound, Mathf.Clamp01(_config.SoundVolume.Value));
				}
			}
		}

		public void Tick(float unscaledDeltaTime)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (_visible)
			{
				_elapsed += Mathf.Max(0f, unscaledDeltaTime);
				float num = Mathf.Clamp01(_elapsed / 0.22f);
				float num2 = Mathf.Clamp01((_duration - _elapsed) / 0.55f);
				_canvasGroup.alpha = Mathf.Min(num, num2);
				float num3 = 1f - EaseOutBack(Mathf.Clamp01(_elapsed / 0.36f));
				_panel.anchoredPosition = new Vector2(0f, -62f - num3 * 55f);
				if (_elapsed >= _duration)
				{
					Hide();
				}
			}
		}

		public void Hide()
		{
			_visible = false;
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
			}
		}

		public void ApplyConfig()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			Color accentColor = _config.GetAccentColor();
			((Graphic)_panelImage).color = new Color(0.006f, 0.012f, 0.016f, 0.94f);
			((Graphic)_accentImage).color = accentColor;
			((Graphic)_title).color = new Color(accentColor.r, accentColor.g, accentColor.b, 0.88f);
			((Graphic)_name).color = new Color(0.96f, 1f, 0.97f, 1f);
			((Graphic)_details).color = new Color(0.72f, 0.82f, 0.76f, 1f);
			if (!_config.Enabled.Value || !_config.ShowAnnouncement.Value)
			{
				Hide();
			}
		}

		private Text CreateText(string name, Transform parent, int fontSize, FontStyle style, TextAnchor alignment)
		{
			//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_0059: 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)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			});
			val.transform.SetParent(parent, false);
			Text component = val.GetComponent<Text>();
			component.font = _font;
			component.fontSize = fontSize;
			component.fontStyle = style;
			component.alignment = alignment;
			component.horizontalOverflow = (HorizontalWrapMode)1;
			component.verticalOverflow = (VerticalWrapMode)0;
			component.supportRichText = true;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private static Image CreateImage(string name, Transform parent, Vector2 position, Vector2 size)
		{
			//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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).raycastTarget = false;
			((Graphic)component).rectTransform.anchoredPosition = position;
			((Graphic)component).rectTransform.sizeDelta = size;
			return component;
		}

		private static void SetRect(RectTransform rect, Vector2 position, Vector2 size, Vector2 pivot)
		{
			//IL_000b: 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_002b: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0f, 1f);
			rect.anchorMax = new Vector2(0f, 1f);
			rect.pivot = pivot;
			rect.anchoredPosition = position;
			rect.sizeDelta = size;
		}

		private static float EaseOutBack(float value)
		{
			float num = value - 1f;
			return 1f + 2.70158f * num * num * num + 1.70158f * num * num;
		}

		private static AudioClip CreateSound()
		{
			int num = Mathf.CeilToInt(19404f);
			float[] array = new float[num];
			for (int i = 0; i < num; i++)
			{
				float num2 = (float)i / 44100f;
				float num3 = ((num2 < 0.14f) ? 392f : ((num2 < 0.28f) ? 523.25f : 783.99f));
				float num4 = Mathf.Clamp01(num2 * 35f) * Mathf.Exp(-4.8f * num2);
				array[i] = (Mathf.Sin(MathF.PI * 2f * num3 * num2) + 0.32f * Mathf.Sin(MathF.PI * 2f * num3 * 2f * num2)) * num4 * 0.16f;
			}
			AudioClip obj = AudioClip.Create("HaulOfFame_Result", num, 1, 44100, false);
			((Object)obj).hideFlags = (HideFlags)61;
			obj.SetData(array, 0);
			return obj;
		}

		public void Dispose()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			if ((Object)(object)_panelSprite != (Object)null)
			{
				Texture2D texture = _panelSprite.texture;
				Object.Destroy((Object)(object)_panelSprite);
				if ((Object)(object)texture != (Object)null)
				{
					Object.Destroy((Object)(object)texture);
				}
			}
			if ((Object)(object)_sound != (Object)null)
			{
				Object.Destroy((Object)(object)_sound);
			}
			if (_ownsFont && (Object)(object)_font != (Object)null)
			{
				Object.Destroy((Object)(object)_font);
			}
		}
	}
	public sealed class TrophyController : IDisposable
	{
		private readonly ModConfig _config;

		private readonly GameBindings _bindings;

		private readonly ManualLogSource _logger;

		private readonly GameObject _root;

		private readonly Transform _modelMount;

		private readonly GameObject _fallbackModel;

		private readonly RectTransform _plaqueCanvas;

		private readonly Image _plaquePanel;

		private readonly Image _plaqueAccent;

		private readonly Text _plaqueText;

		private readonly Light _light;

		private readonly Material _darkMaterial;

		private readonly Material _accentMaterial;

		private readonly Material _fallbackMaterial;

		private readonly Font _font;

		private readonly bool _ownsFont;

		private readonly List<GameObject> _trimObjects = new List<GameObject>();

		private Transform? _anchor;

		private TrophyModelSnapshot? _attachedSnapshot;

		private ChampionData? _champion;

		private float _anchorSearchTimer;

		private float _animationTime;

		private int _lastAnchorSceneHandle = int.MinValue;

		public TrophyController(ModConfig config, GameBindings bindings, ManualLogSource logger)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: 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)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Expected O, but got Unknown
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Expected O, but got Unknown
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			_config = config;
			_bindings = bindings;
			_logger = logger;
			_font = Font.CreateDynamicFontFromOSFont(new string[4] { "Bahnschrift SemiCondensed", "Arial Narrow", "Segoe UI Semibold", "Arial" }, 18);
			if ((Object)(object)_font != (Object)null)
			{
				_ownsFont = true;
			}
			else
			{
				_font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			}
			_root = new GameObject("HaulOfFame_WorldTrophy")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)(object)_root);
			_darkMaterial = CreateMaterial("HaulOfFame_Dark", new Color(0.018f, 0.024f, 0.028f, 1f), Color.black);
			_accentMaterial = CreateMaterial("HaulOfFame_Accent", new Color(0.1f, 0.34f, 0.15f, 1f), new Color(0.2f, 2f, 0.36f, 1f));
			_fallbackMaterial = CreateMaterial("HaulOfFame_Fallback", new Color(0.12f, 0.85f, 0.28f, 0.82f), new Color(0.25f, 2.6f, 0.5f, 1f));
			CreatePrimitive("PedestalBase", (PrimitiveType)2, _root.transform, new Vector3(0f, 0.08f, 0f), new Vector3(0.72f, 0.08f, 0.72f), _darkMaterial);
			CreatePrimitive("PedestalTop", (PrimitiveType)2, _root.transform, new Vector3(0f, 0.19f, 0f), new Vector3(0.55f, 0.045f, 0.55f), _darkMaterial);
			_trimObjects.Add(CreatePrimitive("GlowRingLow", (PrimitiveType)2, _root.transform, new Vector3(0f, 0.145f, 0f), new Vector3(0.64f, 0.012f, 0.64f), _accentMaterial));
			_trimObjects.Add(CreatePrimitive("GlowRingTop", (PrimitiveType)2, _root.transform, new Vector3(0f, 0.245f, 0f), new Vector3(0.48f, 0.012f, 0.48f), _accentMaterial));
			GameObject val = new GameObject("ModelMount")
			{
				hideFlags = (HideFlags)61
			};
			val.transform.SetParent(_root.transform, false);
			val.transform.localPosition = new Vector3(0f, 0.72f, 0f);
			_modelMount = val.transform;
			_fallbackModel = CreatePrimitive("FallbackHologram", (PrimitiveType)0, _modelMount, Vector3.zero, new Vector3(0.52f, 0.72f, 0.52f), _fallbackMaterial);
			GameObject val2 = new GameObject("HologramLight")
			{
				hideFlags = (HideFlags)61
			};
			val2.transform.SetParent(_root.transform, false);
			val2.transform.localPosition = new Vector3(0f, 0.7f, 0.1f);
			_light = val2.AddComponent<Light>();
			_light.type = (LightType)2;
			_light.range = 3.2f;
			_light.intensity = 1.35f;
			(_plaqueCanvas, _plaquePanel, _plaqueAccent, _plaqueText) = CreatePlaque(_root.transform);
			ApplyConfig();
			SetChampionVisualsActive(active: false);
			_root.SetActive(false);
		}

		public void ShowChampion(ChampionData champion, TrophyModelSnapshot? snapshot, string plaqueText)
		{
			DetachSnapshot();
			_champion = champion;
			_attachedSnapshot = ((snapshot != null && snapshot.Valuable.ViewId == champion.Valuable.ViewId) ? snapshot : null);
			if (_attachedSnapshot != null)
			{
				_attachedSnapshot.AttachTo(_modelMount);
			}
			_fallbackModel.SetActive(_attachedSnapshot == null);
			_plaqueText.text = plaqueText;
			SetChampionVisualsActive(active: true);
			_anchorSearchTimer = 0f;
			_animationTime = 0f;
			if (_config.DebugLogging.Value)
			{
				_logger.LogInfo((object)$"[HaulOfFame/Visual] Trophy prepared: view={champion.Valuable.ViewId}, name='{champion.Valuable.Name}', modelCopy={_attachedSnapshot != null}.");
			}
		}

		public void Tick(float unscaledDeltaTime)
		{
			//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_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_048e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: Unknown result type (might be due to invalid IL or missing references)
			//IL_049e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c5: Unknown result type (might be due to invalid IL or missing references)
			bool flag = _champion != null;
			if (!_config.Enabled.Value || !_config.ShowWorldTrophy.Value || (!flag && !_config.ShowEmptyBase.Value))
			{
				_root.SetActive(false);
				return;
			}
			GamePhase phase = _bindings.GetPhase();
			if ((uint)phase <= 1u)
			{
				_root.SetActive(false);
				return;
			}
			if ((Object)(object)_anchor == (Object)null)
			{
				_anchorSearchTimer -= Mathf.Max(0f, unscaledDeltaTime);
				if (_anchorSearchTimer <= 0f)
				{
					_anchorSearchTimer = 0.75f;
					_anchor = _bindings.FindTruckAnchor();
					if ((Object)(object)_anchor != (Object)null)
					{
						Scene scene = ((Component)_anchor).gameObject.scene;
						if (((Scene)(ref scene)).handle != _lastAnchorSceneHandle)
						{
							scene = ((Component)_anchor).gameObject.scene;
							_lastAnchorSceneHandle = ((Scene)(ref scene)).handle;
							ManualLogSource logger = _logger;
							string[] obj = new string[5]
							{
								"[HaulOfFame/Visual] Truck display anchor found: ",
								((Object)_anchor).name,
								" in scene ",
								null,
								null
							};
							scene = ((Component)_anchor).gameObject.scene;
							obj[3] = ((Scene)(ref scene)).name;
							obj[4] = ".";
							logger.LogInfo((object)string.Concat(obj));
						}
					}
				}
			}
			if ((Object)(object)_anchor == (Object)null)
			{
				_root.SetActive(false);
				return;
			}
			try
			{
				Vector3 val = default(Vector3);
				Quaternion val2;
				if (_config.PositionMode.Value == TrophyPositionMode.FixedWorld)
				{
					((Vector3)(ref val))..ctor(Mathf.Clamp(_config.WorldX.Value, -1000f, 1000f), Mathf.Clamp(_config.WorldY.Value, -1000f, 1000f), Mathf.Clamp(_config.WorldZ.Value, -1000f, 1000f));
					val2 = Quaternion.Euler(0f, Mathf.Clamp(_config.RotationY.Value, -360f, 360f), 0f);
				}
				else
				{
					val = _anchor.position + _anchor.right * Mathf.Clamp(_config.OffsetX.Value, -5f, 5f) + _anchor.up * Mathf.Clamp(_config.OffsetY.Value, -5f, 5f) + _anchor.forward * Mathf.Clamp(_config.OffsetZ.Value, -5f, 5f);
					val2 = _anchor.rotation * Quaternion.Euler(0f, Mathf.Clamp(_config.RotationY.Value, -360f, 360f), 0f);
				}
				_root.transform.SetPositionAndRotation(val, val2);
				_root.transform.localScale = Vector3.one * Mathf.Clamp(_config.TrophyScale.Value, 0.25f, 3f);
				if (!_root.activeSelf)
				{
					_root.SetActive(true);
				}
				SetChampionVisualsActive(flag);
			}
			catch (MissingReferenceException)
			{
				_anchor = null;
				_root.SetActive(false);
				return;
			}
			if (!flag)
			{
				return;
			}
			_animationTime += Mathf.Max(0f, unscaledDeltaTime);
			_modelMount.Rotate(Vector3.up, Mathf.Clamp(_config.SpinSpeed.Value, -180f, 180f) * unscaledDeltaTime, (Space)1);
			float num = Mathf.Sin(_animationTime * Mathf.Clamp(_config.BobSpeed.Value, 0f, 10f) * MathF.PI * 2f) * Mathf.Clamp(_config.BobHeight.Value, 0f, 0.3f);
			_modelMount.localPosition = new Vector3(0f, 0.72f + num, 0f);
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				Vector3 val3 = ((Transform)_plaqueCanvas).position - ((Component)main).transform.position;
				if (((Vector3)(ref val3)).sqrMagnitude > 0.001f)
				{
					((Transform)_plaqueCanvas).rotation = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, Vector3.up);
				}
			}
		}

		public void HandleSceneChanged()
		{
			_anchor = null;
			_anchorSearchTimer = 0.25f;
			_root.SetActive(false);
		}

		public void ApplyConfig()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			Color accentColor = _config.GetAccentColor();
			ApplyMaterialColor(_accentMaterial, new Color(accentColor.r * 0.32f, accentColor.g * 0.32f, accentColor.b * 0.32f, 1f), accentColor * 2f);
			ApplyMaterialColor(_fallbackMaterial, new Color(accentColor.r, accentColor.g, accentColor.b, 0.86f), accentColor * 2.7f);
			_light.color = accentColor;
			((Graphic)_plaqueAccent).color = accentColor;
			((Graphic)_plaquePanel).color = new Color(0.006f, 0.012f, 0.016f, 0.93f);
			if (!_config.Enabled.Value || !_config.ShowWorldTrophy.Value)
			{
				_root.SetActive(false);
			}
		}

		public void Clear()
		{
			DetachSnapshot();
			_champion = null;
			_plaqueText.text = string.Empty;
			SetChampionVisualsActive(active: false);
			_anchor = null;
			_root.SetActive(false);
		}

		private void SetChampionVisualsActive(bool active)
		{
			if (((Component)_modelMount).gameObject.activeSelf != active)
			{
				((Component)_modelMount).gameObject.SetActive(active);
			}
			if (((Component)_plaqueCanvas).gameObject.activeSelf != active)
			{
				((Component)_plaqueCanvas).gameObject.SetActive(active);
			}
			if (((Component)_light).gameObject.activeSelf != active)
			{
				((Component)_light).gameObject.SetActive(active);
			}
		}

		private void DetachSnapshot()
		{
			if (_attachedSnapshot == null || (Object)(object)_attachedSnapshot.Root == (Object)null)
			{
				_attachedSnapshot = null;
				return;
			}
			_attachedSnapshot.Root.transform.SetParent((Transform)null, false);
			_attachedSnapshot.Hide();
			_attachedSnapshot = null;
		}

		private (RectTransform canvas, Image panel, Image accent, Text text) CreatePlaque(Transform parent)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("PlaqueCanvas", new Type[2]
			{
				typeof(RectTransform),
				typeof(Canvas)
			});
			((Object)val).hideFlags = (HideFlags)61;
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).localPosition = new Vector3(0f, 1.58f, 0f);
			((Transform)component).localRotation = Quaternion.identity;
			((Transform)component).localScale = Vector3.one * 0.00145f;
			component.sizeDelta = new Vector2(620f, 180f);
			Canvas component2 = val.GetComponent<Canvas>();
			component2.renderMode = (RenderMode)2;
			component2.sortingOrder = 100;
			GameObject val2 = new GameObject("Panel", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val2.transform.SetParent(val.transform, false);
			RectTransform component3 = val2.GetComponent<RectTransform>();
			component3.anchorMin = Vector2.zero;
			component3.anchorMax = Vector2.one;
			component3.offsetMin = Vector2.zero;
			component3.offsetMax = Vector2.zero;
			Image component4 = val2.GetComponent<Image>();
			((Graphic)component4).raycastTarget = false;
			GameObject val3 = new GameObject("Accent", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val3.transform.SetParent(val2.transform, false);
			RectTransform component5 = val3.GetComponent<RectTransform>();
			component5.anchorMin = new Vector2(0f, 0f);
			component5.anchorMax = new Vector2(0f, 1f);
			component5.pivot = new Vector2(0f, 0.5f);
			component5.anchoredPosition = new Vector2(8f, 0f);
			component5.sizeDelta = new Vector2(7f, -18f);
			Image component6 = val3.GetComponent<Image>();
			((Graphic)component6).raycastTarget = false;
			GameObject val4 = new GameObject("Text", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			});
			val4.transform.SetParent(val2.transform, false);
			RectTransform component7 = val4.GetComponent<RectTransform>();
			component7.anchorMin = Vector2.zero;
			component7.anchorMax = Vector2.one;
			component7.offsetMin = new Vector2(30f, 14f);
			component7.offsetMax = new Vector2(-18f, -12f);
			Text component8 = val4.GetComponent<Text>();
			component8.font = _font;
			component8.fontSize = 24;
			component8.fontStyle = (FontStyle)1;
			component8.alignment = (TextAnchor)3;
			((Graphic)component8).color = new Color(0.94f, 1f, 0.96f, 1f);
			component8.supportRichText = true;
			component8.horizontalOverflow = (HorizontalWrapMode)0;
			component8.verticalOverflow = (VerticalWrapMode)0;
			((Graphic)component8).raycastTarget = false;
			return (canvas: component, panel: component4, accent: component6, text: component8);
		}

		private static GameObject CreatePrimitive(string name, PrimitiveType primitive, Transform parent, Vector3 localPosition, Vector3 localScale, Material material)
		{
			//IL_0000: 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_0034: 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 obj = GameObject.CreatePrimitive(primitive);
			((Object)obj).name = name;
			((Object)obj).hideFlags = (HideFlags)61;
			obj.transform.SetParent(parent, false);
			obj.transform.localPosition = localPosition;
			obj.transform.localRotation = Quaternion.identity;
			obj.transform.localScale = localScale;
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Renderer component2 = obj.GetComponent<Renderer>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.sharedMaterial = material;
			}
			return obj;
		}

		private static Material CreateMaterial(string name, Color color, Color emission)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_007a: Expected O, but got Unknown
			Shader obj = Shader.Find("Standard") ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Diffuse") ?? Shader.Find("Sprites/Default") ?? Shader.Find("UI/Default");
			if ((Object)(object)obj == (Object)null)
			{
				throw new InvalidOperationException("No compatible built-in shader was found for the trophy display.");
			}
			Material val = new Material(obj)
			{
				name = name,
				color = color,
				hideFlags = (HideFlags)61
			};
			ApplyMaterialColor(val, color, emission);
			return val;
		}

		private static void ApplyMaterialColor(Material material, Color color, Color emission)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			material.color = color;
			if (material.HasProperty("_EmissionColor"))
			{
				material.EnableKeyword("_EMISSION");
				material.SetColor("_EmissionColor", emission);
			}
		}

		public void Dispose()
		{
			DetachSnapshot();
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			Object.Destroy((Object)(object)_darkMaterial);
			Object.Destroy((Object)(object)_accentMaterial);
			Object.Destroy((Object)(object)_fallbackMaterial);
			if (_ownsFont && (Object)(object)_font != (Object)null)
			{
				Object.Destroy((Object)(object)_font);
			}
			_trimObjects.Clear();
		}
	}
	public sealed class TrophyModelSnapshot : IDisposable
	{
		private readonly List<Mesh> _ownedMeshes = new List<Mesh>();

		private bool _disposed;

		public CapturedValuable Valuable { get; }

		public GameObject Root { get; }

		private TrophyModelSnapshot(CapturedValuable valuable, GameObject root, List<Mesh> ownedMeshes)
		{
			Valuable = valuable;
			Root = root;
			_ownedMeshes.AddRange(ownedMeshes);
		}

		public static bool TryCreate(CapturedValuable valuable, PhysGrabObject source, ManualLogSource logger, out TrophyModelSnapshot snapshot)
		{
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Expected O, but got Unknown
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			snapshot = null;
			if ((Object)(object)source == (Object)null)
			{
				return false;
			}
			List<GameObject> list = new List<GameObject>();
			List<Renderer> list2 = new List<Renderer>();
			List<Mesh> list3 = new List<Mesh>();
			try
			{
				MeshFilter[] componentsInChildren = ((Component)source).GetComponentsInChildren<MeshFilter>(true);
				foreach (MeshFilter val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sharedMesh == (Object)null) && ((Component)val).gameObject.activeInHierarchy)
					{
						MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
						if (!((Object)(object)component == (Object)null) && ((Renderer)component).enabled)
						{
							GameObject val2 = CreateMeshObject(((Component)val).transform, val.sharedMesh, ((Renderer)component).sharedMaterials);
							list.Add(val2);
							list2.Add((Renderer)(object)val2.GetComponent<MeshRenderer>());
						}
					}
				}
				SkinnedMeshRenderer[] componentsInChildren2 = ((Component)source).GetComponentsInChildren<SkinnedMeshRenderer>(true);
				foreach (SkinnedMeshRenderer val3 in componentsInChildren2)
				{
					if (!((Object)(object)val3 == (Object)null) && ((Renderer)val3).enabled && ((Component)val3).gameObject.activeInHierarchy)
					{
						Mesh val4 = new Mesh
						{
							name = "HaulOfFame_BakedMesh",
							hideFlags = (HideFlags)61
						};
						val3.BakeMesh(val4);
						if (val4.vertexCount == 0)
						{
							Object.Destroy((Object)(object)val4);
							continue;
						}
						list3.Add(val4);
						GameObject val5 = CreateMeshObject(((Component)val3).transform, val4, ((Renderer)val3).sharedMaterials);
						list.Add(val5);
						list2.Add((Renderer)(object)val5.GetComponent<MeshRenderer>());
					}
				}
				if (list2.Count == 0)
				{
					foreach (GameObject item in list)
					{
						Object.Destroy((Object)(object)item);
					}
					foreach (Mesh item2 in list3)
					{
						Object.Destroy((Object)(object)item2);
					}
					return false;
				}
				Bounds bounds = list2[0].bounds;
				for (int j = 1; j < list2.Count; j++)
				{
					((Bounds)(ref bounds)).Encapsulate(list2[j].bounds);
				}
				GameObject val6 = new GameObject("HaulOfFame_Model_" + valuable.ViewId)
				{
					hideFlags = (HideFlags)61
				};
				val6.transform.position = ((Bounds)(ref bounds)).center;
				foreach (GameObject item3 in list)
				{
					item3.transform.SetParent(val6.transform, true);
				}
				val6.transform.position = Vector3.zero;
				val6.transform.rotation = Quaternion.identity;
				float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z));
				val6.transform.localScale = Vector3.one * ((num > 0.001f) ? (1f / num) : 1f);
				Object.DontDestroyOnLoad((Object)(object)val6);
				val6.SetActive(false);
				snapshot = new TrophyModelSnapshot(valuable, val6, list3);
				return true;
			}
			catch (Exception ex)
			{
				foreach (GameObject item4 in list)
				{
					if ((Object)(object)item4 != (Object)null)
					{
						Object.Destroy((Object)(object)item4);
					}
				}
				foreach (Mesh item5 in list3)
				{
					if ((Object)(object)item5 != (Object)null)
					{
						Object.Destroy((Object)(object)item5);
					}
				}
				logger.LogWarning((object)("[HaulOfFame/Visual] Model snapshot failed for '" + valuable.Name + "': " + ex.GetType().Name + ": " + ex.Message));
				return false;
			}
		}

		public void AttachTo(Transform parent)
		{
			//IL_0034: 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)
			if (!_disposed && !((Object)(object)Root == (Object)null))
			{
				Root.transform.SetParent(parent, false);
				Root.transform.localPosition = Vector3.zero;
				Root.transform.localRotation = Quaternion.identity;
				Root.SetActive(true);
			}
		}

		public void Hide()
		{
			if (!_disposed && (Object)(object)Root != (Object)null)
			{
				Root.SetActive(false);
			}
		}

		private static GameObject CreateMeshObject(Transform sourceTransform, Mesh mesh, Material[] materials)
		{
			//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_0012: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			GameObject val = new GameObject("HaulOfFame_RenderPart")
			{
				hideFlags = (HideFlags)61
			};
			val.transform.position = sourceTransform.position;
			val.transform.rotation = sourceTransform.rotation;
			val.transform.localScale = sourceTransform.lossyScale;
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			MeshRenderer obj = val.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterials = materials;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)obj).receiveShadows = true;
			((Renderer)obj).lightProbeUsage = (LightProbeUsage)1;
			return val;
		}

		public void Dispose()
		{
			if (_disposed)
			{
				return;
			}
			_disposed = true;
			if ((Object)(object)Root != (Object)null)
			{
				Object.Destroy((Object)(object)Root);
			}
			foreach (Mesh ownedMesh in _ownedMeshes)
			{
				if ((Object)(object)ownedMesh != (Object)null)
				{
					Object.Destroy((Object)(object)ownedMesh);
				}
			}
			_ownedMeshes.Clear();
		}
	}
}
namespace HaulOfFame.Network
{
	public sealed class HaulNetwork : IDisposable
	{
		private enum MessageType : byte
		{
			Hello,
			PrepareValuable,
			Contribution,
			Champion
		}

		private const byte EventCode = 182;

		private const string Signature = "com.juanma.hauloffame";

		private const byte ProtocolVersion = 1;

		private const float MinimumContributionInterval = 0.02f;

		private readonly ModConfig _config;

		private readonly ManualLogSource _logger;

		private readonly HashSet<int> _moddedActors = new HashSet<int>();

		private readonly Dictionary<long, float> _lastContributionTime = new Dictionary<long, float>();

		private LoadBalancingClient? _subscribedClient;

		private Room? _trackedRoom;

		public event Action<int, int>? PrepareReceived;

		public event Action<int, int, float>? ContributionReceived;

		public event Action<ChampionData>? ChampionReceived;

		public HaulNetwork(ModConfig config, ManualLogSource logger)
		{
			_config = config;
			_logger = logger;
			RefreshSubscription();
		}

		public void Tick()
		{
			RefreshSubscription();
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (currentRoom == _trackedRoom)
			{
				return;
			}
			_trackedRoom = currentRoom;
			_moddedActors.Clear();
			_lastContributionTime.Clear();
			if (currentRoom != null && PhotonNetwork.LocalPlayer != null)
			{
				_moddedActors.Add(PhotonNetwork.LocalPlayer.ActorNumber);
				SendHello();
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)$"[HaulOfFame/Network] Entered room '{currentRoom.Name}' as actor {PhotonNetwork.LocalPlayer.ActorNumber}; presence announced.");
				}
			}
		}

		public void BroadcastPrepare(int viewId, int extractionPointViewId)
		{
			if (CanSend() && viewId > 0)
			{
				object[] payload = new object[6]
				{
					"com.juanma.hauloffame",
					(byte)1,
					(byte)1,
					viewId,
					Mathf.Max(0, extractionPointViewId),
					PhotonNetwork.ServerTimestamp
				};
				Raise(payload, (ReceiverGroup)0);
			}
		}

		public void SendContribution(int viewId, float score)
		{
			if (CanSend() && viewId > 0 && IsFinite(score))
			{
				object[] payload = new object[6]
				{
					"com.juanma.hauloffame",
					(byte)1,
					(byte)2,
					viewId,
					Mathf.Clamp(score, 0f, 1000f),
					PhotonNetwork.ServerTimestamp
				};
				Raise(payload, (ReceiverGroup)2);
			}
		}

		public void BroadcastChampion(ChampionData champion)
		{
			if (CanSend())
			{
				object[] payload = new object[11]
				{
					"com.juanma.hauloffame",
					(byte)1,
					(byte)3,
					champion.Valuable.ViewId,
					CapturedValuable.SanitizeName(champion.Valuable.Name),
					champion.Valuable.CurrentValue,
					champion.Valuable.OriginalValue,
					champion.ContributorActors,
					champion.ContributorScores,
					champion.AttributionComplete,
					PhotonNetwork.ServerTimestamp
				};
				Raise(payload, (ReceiverGroup)0);
			}
		}

		public bool AllPlayersHaveMod()
		{
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (currentRoom == null)
			{
				return true;
			}
			foreach (int key in currentRoom.Players.Keys)
			{
				if (!_moddedActors.Contains(key))
				{
					return false;
				}
			}
			return true;
		}

		private void SendHello()
		{
			if (CanSend())
			{
				object[] payload = new object[4]
				{
					"com.juanma.hauloffame",
					(byte)1,
					(byte)0,
					PhotonNetwork.ServerTimestamp
				};
				Raise(payload, (ReceiverGroup)0);
			}
		}

		private bool Raise(object[] payload, ReceiverGroup receivers)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = receivers,
				CachingOption = (EventCaching)0
			};
			bool flag = PhotonNetwork.RaiseEvent((byte)182, (object)payload, val, SendOptions.SendReliable);
			if (_config.DebugLogging.Value && !flag)
			{
				_logger.LogWarning((object)$"[HaulOfFame/Network] Photon rejected outgoing message type {payload[2]}.");
			}
			return flag;
		}

		private void RefreshSubscription()
		{
			LoadBalancingClient networkingClient = PhotonNetwork.NetworkingClient;
			if (networkingClient != _subscribedClient)
			{
				if (_subscribedClient != null)
				{
					_subscribedClient.EventReceived -= OnEventReceived;
				}
				_subscribedClient = networkingClient;
				if (_subscribedClient != null)
				{
					_subscribedClient.EventReceived += OnEventReceived;
					_logger.LogInfo((object)"[HaulOfFame/Network] Photon custom-event listener attached.");
				}
			}
		}

		private void OnEventReceived(EventData eventData)
		{
			if (eventData.Code != 182 || !(eventData.CustomData is object[] array) || array.Length < 4 || !(array[0] is string text) || text != "com.juanma.hauloffame" || !(array[1] is byte b) || b != 1 || !(array[2] is byte b2) || !Enum.IsDefined(typeof(MessageType), b2))
			{
				return;
			}
			int sender = eventData.Sender;
			if (sender <= 0)
			{
				return;
			}
			switch ((MessageType)b2)
			{
			case MessageType.Hello:
				_moddedActors.Add(sender);
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)$"[HaulOfFame/Network] Actor {sender} reported compatible protocol {b}.");
				}
				break;
			case MessageType.PrepareValuable:
				ReceivePrepare(sender, array);
				break;
			case MessageType.Contribution:
				ReceiveContribution(sender, array);
				break;
			case MessageType.Champion:
				ReceiveChampion(sender, array);
				break;
			}
		}

		private void ReceivePrepare(int sender, object[] payload)
		{
			if (payload.Length == 6 && payload[3] is int num && payload[4] is int num2 && payload[5] is int timestamp && num > 0 && IsMasterActor(sender) && Fresh(timestamp, 15000))
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)$"[HaulOfFame/Network] Host prepared extracted valuable view={num}.");
				}
				this.PrepareReceived?.Invoke(num, Mathf.Max(0, num2));
			}
		}

		private void ReceiveContribution(int sender, object[] payload)
		{
			if (payload.Length == 6 && payload[3] is int num && payload[4] is float num2 && payload[5] is int timestamp && PhotonNetwork.IsMasterClient && num > 0 && IsFinite(num2) && !(num2 < 0f) && !(num2 > 1000f) && Fresh(timestamp, 20000))
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				long key = ((long)sender << 32) | (uint)num;
				if (!_lastContributionTime.TryGetValue(key, out var value) || !(realtimeSinceStartup - value < 0.02f))
				{
					_lastContributionTime[key] = realtimeSinceStartup;
					this.ContributionReceived?.Invoke(sender, num, num2);
				}
			}
		}

		private void ReceiveChampion(int sender, object[] payload)
		{
			if (payload.Length != 11 || !IsMasterActor(sender) || !(payload[3] is int num) || !(payload[4] is string name) || !(payload[5] is int num2) || !(payload[6] is int num3) || !(payload[7] is int[] array) || !(payload[8] is float[] array2) || !(payload[9] is bool attributionComplete) || !(payload[10] is int timestamp) || num <= 0 || num2 < 0 || num3 < num2 || array.Length != array2.Length || array.Length > 32 || !Fresh(timestamp, 30000))
			{
				return;
			}
			float[] array3 = array2;
			foreach (float num4 in array3)
			{
				if (!IsFinite(num4) || num4 < 0f || num4 > 1000f)
				{
					return;
				}
			}
			ChampionData obj = new ChampionData(new CapturedValuable(num, name, num2, num3), array, array2, attributionComplete);
			this.ChampionReceived?.Invoke(obj);
		}

		private static bool CanSend()
		{
			if (PhotonNetwork.InRoom)
			{
				return PhotonNetwork.IsConnectedAndReady;
			}
			return false;
		}

		private static bool IsMasterActor(int actorNumber)
		{
			Player masterClient = PhotonNetwork.MasterClient;
			if (masterClient != null)
			{
				return masterClient.ActorNumber == actorNumber;
			}
			return false;
		}

		private static bool Fresh(int timestamp, int maximumAgeMilliseconds)
		{
			int num = PhotonNetwork.ServerTimestamp - timestamp;
			if (num >= -2000)
			{
				return num <= maximumAgeMilliseconds;
			}
			return false;
		}

		private static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		public void Dispose()
		{
			if (_subscribedClient != null)
			{
				_subscribedClient.EventReceived -= OnEventReceived;
			}
			_subscribedClient = null;
			_trackedRoom = null;
			_moddedActors.Clear();
			_lastContributionTime.Clear();
			this.PrepareReceived = null;
			this.ContributionReceived = null;
			this.ChampionReceived = null;
		}
	}
}
namespace HaulOfFame.Core
{
	public sealed class CapturedValuable
	{
		public int ViewId { get; }

		public string Name { get; }

		public int CurrentValue { get; }

		public int OriginalValue { get; }

		public float RetainedPercent
		{
			get
			{
				if (OriginalValue > 0)
				{
					return Mathf.Clamp((float)CurrentValue * 100f / (float)OriginalValue, 0f, 999f);
				}
				return 100f;
			}
		}

		public CapturedValuable(int viewId, string name, int currentValue, int originalValue)
		{
			ViewId = viewId;
			Name = SanitizeName(name);
			CurrentValue = Mathf.Max(0, currentValue);
			OriginalValue = Mathf.Max(CurrentValue, originalValue);
		}

		public bool Beats(CapturedValuable? other)
		{
			if (other == null)
			{
				return true;
			}
			if (CurrentValue != other.CurrentValue)
			{
				return CurrentValue > other.CurrentValue;
			}
			int num = RetainedPercent.CompareTo(other.RetainedPercent);
			if (num != 0)
			{
				return num > 0;
			}
			return ViewId < other.ViewId;
		}

		public static string SanitizeName(string? value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return "VALUABLE";
			}
			List<char> list = new List<char>(Mathf.Min(value.Length, 64));
			string text = value.Trim();
			foreach (char c in text)
			{
				if (list.Count >= 64)
				{
					break;
				}
				if (!char.IsControl(c) && c != '<' && c != '>')
				{
					list.Add(c);
				}
			}
			if (list.Count != 0)
			{
				return new string(list.ToArray());
			}
			return "VALUABLE";
		}
	}
	public sealed class ChampionData
	{
		public CapturedValuable Valuable { get; }

		public int[] ContributorActors { get; }

		public float[] ContributorScores { get; }

		public bool AttributionComplete { get; }

		public ChampionData(CapturedValuable valuable, int[]? contributorActors, float[]? contributorScores, bool attributionComplete)
		{
			Valuable = valuable;
			ContributorActors = contributorActors ?? Array.Empty<int>();
			ContributorScores = contributorScores ?? Array.Empty<float>();
			AttributionComplete = attributionComplete;
		}
	}
	public enum GamePhase
	{
		Unavailable,
		MainMenu,
		Mission,
		Shop,
		Lobby,
		Other
	}
	public sealed class GameBindings
	{
		private readonly ManualLogSource _logger;

		private FieldInfo? _valuableCurrentField;

		private FieldInfo? _valuableOriginalField;

		private FieldInfo? _valuableValueSetField;

		private FieldInfo? _runStartedField;

		private FieldInfo? _extractionPointsField;

		private FieldInfo? _extractionPointsCompletedField;

		private FieldInfo? _extractionPointCurrentField;

		private bool _readErrorLogged;

		public GameBindings(ManualLogSource logger)
		{
			_logger = logger;
		}

		public bool Resolve()
		{
			_valuableCurrentField = ResolveField(typeof(ValuableObject), "dollarValueCurrent", typeof(float));
			_valuableOriginalField = ResolveField(typeof(ValuableObject), "dollarValueOriginal", typeof(float));
			_valuableValueSetField = ResolveField(typeof(ValuableObject), "dollarValueSet", typeof(bool));
			_runStartedField = ResolveField(typeof(RunManager), "runStarted", typeof(bool));
			_extractionPointsField = ResolveField(typeof(RoundDirector), "extractionPoints", typeof(int));
			_extractionPointsCompletedField = ResolveField(typeof(RoundDirector), "extractionPointsCompleted", typeof(int));
			_extractionPointCurrentField = ResolveField(typeof(RoundDirector), "extractionPointCurrent", typeof(ExtractionPoint));
			if (_valuableCurrentField != null && _valuableOriginalField != null && _runStartedField != null && _extractionPointsField != null)
			{
				return _extractionPointsCompletedField != null;
			}
			return false;
		}

		public bool TryCapture(ExtractionPoint extractionPoint, PhysGrabObject physObject, out CapturedValuable captured, out float localHaulScore, out string failure)
		{
			localHaulScore = 0f;
			if ((Object)(object)extractionPoint == (Object)null || (Object)(object)physObject == (Object)null)
			{
				captured = null;
				failure = "missing extraction point or physics object";
				return false;
			}
			if (!TryCaptureMetadata(physObject, out captured, out ValuableObject valuable, out failure))
			{
				return false;
			}
			try
			{
				localHaulScore = valuable.GetLocalPlayerHaulScore(((Component)extractionPoint).gameObject);
				if (!IsFinite(localHaulScore) || localHaulScore < 0f)
				{
					localHaulScore = 0f;
				}
			}
			catch (Exception ex)
			{
				localHaulScore = 0f;
				if (!_readErrorLogged)
				{
					_readErrorLogged = true;
					_logger.LogWarning((object)("[HaulOfFame/Bindings] Could not read vanilla haul score: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
			return true;
		}

		public bool TryCaptureStored(PhysGrabObject physObject, out CapturedValuable captured, out float localHaulScore, out string failure)
		{
			localHaulScore = 0f;
			if ((Object)(object)physObject == (Object)null)
			{
				captured = null;
				failure = "missing stored physics object";
				return false;
			}
			if (!TryCaptureMetadata(physObject, out captured, out ValuableObject valuable, out failure))
			{
				return false;
			}
			try
			{
				ExtractionPoint[] array = Object.FindObjectsOfType<ExtractionPoint>();
				foreach (ExtractionPoint val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						float localPlayerHaulScore = valuable.GetLocalPlayerHaulScore(((Component)val).gameObject);
						if (IsFinite(localPlayerHaulScore) && localPlayerHaulScore > localHaulScore)
						{
							localHaulScore = localPlayerHaulScore;
						}
					}
				}
			}
			catch (Exception ex)
			{
				localHaulScore = 0f;
				if (!_readErrorLogged)
				{
					_readErrorLogged = true;
					_logger.LogWarning((object)("[HaulOfFame/Bindings] Could not read stored valuable haul score: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
			return true;
		}

		private bool TryCaptureMetadata(PhysGrabObject physObject, out CapturedValuable captured, out ValuableObject valuable, out string failure)
		{
			captured = null;
			valuable = null;
			failure = string.Empty;
			valuable = ((Component)physObject).GetComponent<ValuableObject>() ?? ((Component)physObject).GetComponentInChildren<ValuableObject>();
			if ((Object)(object)valuable == (Object)null)
			{
				failure = "object is not a ValuableObject";
				return false;
			}
			if (_valuableValueSetField != null && TryRead<bool>(_valuableValueSetField, valuable, out var value) && !value)
			{
				failure = "valuable value has not been initialized";
				return false;
			}
			if (!TryRead<float>(_valuableCurrentField, valuable, out var value2) || !IsFinite(value2) || value2 < 0f)
			{
				failure = "invalid current value";
				return false;
			}
			float num = value2;
			if (TryRead<float>(_valuableOriginalField, valuable, out var value3) && IsFinite(value3) && value3 > 0f)
			{
				num = Mathf.Max(value2, value3);
			}
			PhotonView val = ((Component)physObject).GetComponent<PhotonView>() ?? ((Component)physObject).GetComponentInParent<PhotonView>() ?? ((Component)valuable).GetComponent<PhotonView>();
			int viewId = (((Object)(object)val != (Object)null && val.ViewID > 0) ? val.ViewID : Mathf.Abs(((Object)physObject).GetInstanceID()));
			captured = new CapturedValuable(viewId, CleanObjectName(((Object)((Component)valuable).gameObject).name, "VALUABLE"), Mathf.RoundToInt(value2), Mathf.RoundToInt(num));
			return true;
		}

		public bool IsLastExtractionCompleted(RoundDirector? director, out int completed, out int total)
		{
			completed = 0;
			total = 0;
			if ((Object)(object)director == (Object)null || !TryRead<int>(_extractionPointsCompletedField, director, out completed) || !TryRead<int>(_extractionPointsField, director, out total))
			{
				return false;
			}
			if (total > 0)
			{
				return completed >= total;
			}
			return false;
		}

		public GamePhase GetPhase()
		{
			try
			{
				if (SemiFunc.IsMainMenu())
				{
					return GamePhase.MainMenu;
				}
				RunManager instance = RunManager.instance;
				if ((Object)(object)instance == (Object)null || !TryRead<bool>(_runStartedField, instance, out var value) || !value)
				{
					return GamePhase.Unavailable;
				}
				if (SemiFunc.RunIsLevel())
				{
					return GamePhase.Mission;
				}
				if (SemiFunc.RunIsShop())
				{
					return GamePhase.Shop;
				}
				if (SemiFunc.RunIsLobby())
				{
					return GamePhase.Lobby;
				}
				return GamePhase.Other;
			}
			catch
			{
				return GamePhase.Unavailable;
			}
		}

		public Transform? FindTruckAnchor()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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)
			try
			{
				TruckScreenText val = Object.FindObjectOfType<TruckScreenText>();
				Scene scene;
				if ((Object)(object)val != (Object)null)
				{
					scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						return ((Component)val).transform;
					}
				}
				TruckScreenOpen val2 = Object.FindObjectOfType<TruckScreenOpen>();
				if ((Object)(object)val2 != (Object)null)
				{
					scene = ((Component)val2).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						return ((Component)val2).transform;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public ExtractionPoint? FindActiveExtractionPoint(int preferredViewId = 0)
		{
			if (preferredViewId > 0)
			{
				try
				{
					PhotonView val = PhotonView.Find(preferredViewId);
					ExtractionPoint val2 = (((Object)(object)val != (Object)null) ? (((Component)val).GetComponent<ExtractionPoint>() ?? ((Component)val).GetComponentInParent<ExtractionPoint>()) : null);
					if ((Object)(object)val2 != (Object)null)
					{
						return val2;
					}
				}
				catch
				{
				}
			}
			try
			{
				RoundDirector instance = RoundDirector.instance;
				if ((Object)(object)instance != (Object)null && TryRead<ExtractionPoint>(_extractionPointCurrentField, instance, out var value) && (Object)(object)value != (Object)null)
				{
					return value;
				}
			}
			catch
			{
			}
			try
			{
				ExtractionPoint[] array = Object.FindObjectsOfType<ExtractionPoint>();
				foreach (ExtractionPoint val3 in array)
				{
					if ((Object)(object)val3 != (Object)null && !val3.isLocked)
					{
						return val3;
					}
				}
			}
			catch
			{
			}
			return null;
		}

		public string GetActorName(int actorNumber)
		{
			if (actorNumber > 0)
			{
				try
				{
					Room currentRoom = PhotonNetwork.CurrentRoom;
					if (currentRoom != null && currentRoom.Players.TryGetValue(actorNumber, out var value) && !string.IsNullOrWhiteSpace(value.NickName))
					{
						return CapturedValuable.SanitizeName(value.NickName);
					}
				}
				catch
				{
				}
			}
			try
			{
				PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
				string value2 = (((Object)(object)val != (Object)null) ? SemiFunc.PlayerGetName(val) : null);
				if (!string.IsNullOrWhiteSpace(value2))
				{
					return CapturedValuable.SanitizeName(value2);
				}
			}
			catch
			{
			}
			return "PLAYER";
		}

		public static string CleanObjectName(string? rawName, string fallback)
		{
			if (string.IsNullOrWhiteSpace(rawName))
			{
				return fallback;
			}
			string text = rawName.Replace("(Clone)", string.Empty).Trim();
			string[] array = new string[5] { "Valuable ", "Valuable_", "Valuable-", "Prefab ", "Object " };
			foreach (string text2 in array)
			{
				if (text.StartsWith(text2, StringComparison.OrdinalIgnoreCase))
				{
					text = text.Substring(text2.Length);
					break;
				}
			}
			text = text.Replace('_', ' ').Replace('-', ' ');
			StringBuilder stringBuilder = new StringBuilder(text.Length + 8);
			for (int j = 0; j < text.Length; j++)
			{
				char c = text[j];
				if (j > 0 && char.IsUpper(c) && char.IsLower(text[j - 1]))
				{
					stringBuilder.Append(' ');
				}
				stringBuilder.Append(c);
			}
			string value = stringBuilder.ToString().Trim();
			if (!string.IsNullOrWhiteSpace(value))
			{
				return CapturedValuable.SanitizeName(value);
			}
			return fallback;
		}

		private FieldInfo? ResolveField(Type type, string name, Type expectedType)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if (fieldInfo == null || fieldInfo.FieldType != expectedType)
			{
				_logger.LogWarning((object)("[HaulOfFame/Bindings] Missing field " + type.Name + "." + name + " (" + expectedType.Name + ")."));
				return null;
			}
			return fieldInfo;
		}

		private bool TryRead<T>(FieldInfo? field, object target, out T value)
		{
			value = default(T);
			if (field == null || target == null)
			{
				return false;
			}
			try
			{
				if (field.GetValue(target) is T val)
				{
					value = val;
					return true;
				}
			}
			catch (Exception ex)
			{
				if (!_readErrorLogged)
				{
					_readErrorLogged = true;
					_logger.LogWarning((object)("[HaulOfFame/Bindings] Reflection read failed: " + ex.GetType().Name + ": " + ex.Message));
				}
			}
			return false;
		}

		private static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	public sealed class HaulController : IDisposable
	{
		private const float FinalizationDelay = 1.35f;

		private readonly ModConfig _config;

		private readonly GameBindings _bindings;

		private readonly ManualLogSource _logger;

		private readonly HaulNetwork _network;

		private readonly AnnouncementHud _announcement;

		private readonly TrophyController _trophy;

		private readonly Dictionary<int, CapturedValuable> _candidates = new Dictionary<int, CapturedValuable>();

		private readonly Dictionary<int, Dictionary<int, float>> _contributions = new Dictionary<int, Dictionary<int, float>>();

		private readonly Dictionary<int, Dictionary<int, CapturedValuable>> _storedCandidatesByBox = new Dictionary<int, Dictionary<int, CapturedValuable>>();

		private readonly Dictionary<int, TrophyModelSnapshot> _storedBestSnapshotsByBox = new Dictionary<int, TrophyModelSnapshot>();

		private readonly HashSet<int> _capturedViewIds = new HashSet<int>();

		private readonly HashSet<int> _storedViewIds = new HashSet<int>();

		private TrophyModelSnapshot? _bestSnapshot;

		private ChampionData? _champion;

		private GamePhase _phase;

		private float _finalizationTime = -1f;

		private int _missionSceneHandle = int.MinValue;

		private int _lastTickFrame = -1;

		private bool _disposed;

		public HaulController(ModConfig config, GameBindings bindings, ManualLogSource logger)
		{
			_config = config;
			_bindings = bindings;
			_logger = logger;
			_network = new HaulNetwork(config, logger);
			_announcement = new AnnouncementHud(config);
			_trophy = new TrophyController(config, bindings, logger);
			_network.PrepareReceived += OnPrepareReceived;
			_network.ContributionReceived += OnContributionReceived;
			_network.ChampionReceived += OnChampionReceived;
			_config.Changed += OnConfigChanged;
		}

		public void Tick(float unscaledDeltaTime)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || _lastTickFrame == Time.frameCount)
			{
				return;
			}
			_lastTickFrame = Time.frameCount;
			_config.PollForExternalChanges(unscaledDeltaTime);
			_network.Tick();
			_announcement.Tick(unscaledDeltaTime);
			_trophy.Tick(unscaledDeltaTime);
			GamePhase phase = _bindings.GetPhase();
			Scene activeScene = SceneManager.GetActiveScene();
			if (phase != _phase)
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)$"[HaulOfFame/Lifecycle] Phase changed: {_phase} -> {phase}, scene={((Scene)(ref activeScene)).name}[{((Scene)(ref activeScene)).buildIndex}].");
				}
				_phase = phase;
			}
			switch (phase)
			{
			case GamePhase.MainMenu:
				if (_missionSceneHandle != int.MinValue || _champion != null || _candidates.Count > 0)
				{
					ResetAll("returned to main menu");
				}
				return;
			case GamePhase.Mission:
				if (((Scene)(ref activeScene)).handle != _missionSceneHandle)
				{
					BeginMission(activeScene);
				}
				break;
			}
			if (_finalizationTime > 0f && Time.realtimeSinceStartup >= _finalizationTime && IsAuthority())
			{
				_finalizationTime = -1f;
				FinalizeChampion();
			}
		}

		public void OnValuableExtracting(ExtractionPoint extractionPoint, PhysGrabObject physObject)
		{
			if (!_disposed && _config.Enabled.Value && !((Object)(object)extractionPoint == (Object)null) && !((Object)(object)physObject == (Object)null) && _bindings.GetPhase() == GamePhase.Mission && IsAuthority())
			{
				PhotonView val = ((Component)physObject).GetComponent<PhotonView>() ?? ((Component)physObject).GetComponentInParent<PhotonView>();
				int num = (((Object)(object)val != (Object)null) ? val.ViewID : 0);
				PhotonView val2 = ((Component)extractionPoint).GetComponent<PhotonView>() ?? ((Component)extractionPoint).GetComponentInParent<PhotonView>();
				int extractionPointViewId = (((Object)(object)val2 != (Object)null) ? val2.ViewID : 0);
				CaptureLocal(extractionPoint, physObject, "host extraction hook");
				if (PhotonNetwork.InRoom && num > 0)
				{
					_network.BroadcastPrepare(num, extractionPointViewId);
				}
			}
		}

		public void OnExtractionCompleted(RoundDirector director)
		{
			if (_disposed || !_config.Enabled.Value || !IsAuthority())
			{
				return;
			}
			int completed;
			int total;
			bool flag = _bindings.IsLastExtractionCompleted(director, out completed, out total);
			_logger.LogInfo((object)$"[HaulOfFame/Extraction] Extraction completed: {completed}/{total}, captured={_candidates.Count}, final={flag}.");
			if (flag)
			{
				_finalizationTime = Time.realtimeSinceStartup + 1.35f;
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)$"[HaulOfFame/Extraction] Final result scheduled in {1.35f:0.00}s to receive remaining contribution reports.");
				}
			}
		}

		public void OnValuableStored(ItemValuableBox box, PhysGrabObject physObject)
		{
			if (_disposed || !_config.Enabled.Value || (Object)(object)box == (Object)null || (Object)(object)physObject == (Object)null || _bindings.GetPhase() != GamePhase.Mission)
			{
				return;
			}
			if (!_bindings.TryCaptureStored(physObject, out CapturedValuable captured, out float localHaulScore, out string failure))
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogWarning((object)("[HaulOfFame/Hauler] Ignored absorbed target: " + failure + "."));
				}
			}
			else if (_storedViewIds.Add(captured.ViewId))
			{
				PhotonView val = ((Component)box).GetComponent<PhotonView>() ?? ((Component)box).GetComponentInParent<PhotonView>();
				int num = (((Object)(object)val != (Object)null && val.ViewID > 0) ? val.ViewID : Mathf.Abs(((Object)box).GetInstanceID()));
				if (!_storedCandidatesByBox.TryGetValue(num, out Dictionary<int, CapturedValuable> value))
				{
					value = new Dictionary<int, CapturedValuable>();
					_storedCandidatesByBox[num] = value;
				}
				value[captured.ViewId] = captured;
				if ((!_storedBestSnapshotsByBox.TryGetValue(num, out TrophyModelSnapshot value2) || captured.Beats(value2.Valuable)) && TrophyModelSnapshot.TryCreate(captured, physObject, _logger, out TrophyModelSnapshot snapshot))
				{
					value2?.Dispose();
					_storedBestSnapshotsByBox[num] = snapshot;
				}
				int actorNumber = ((PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0);
				RecordContribution(actorNumber, captured.ViewId, localHaulScore);
				if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
				{
					_network.SendContribution(captured.ViewId, localHaulScore);
				}
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)$"[HaulOfFame/Hauler] Stored '{captured.Name}', view={captured.ViewId}, box={num}, value=${captured.CurrentValue:N0}, localScore={localHaulScore:0.###}.");
				}
			}
		}

		public void OnValuableBoxExtracted(ItemValuableBox box)
		{
			if (_disposed || !_config.Enabled.Value || (Object)(object)box == (Object)null || !IsAuthority())
			{
				return;
			}
			PhotonView val = ((Component)box).GetComponent<PhotonView>() ?? ((Component)box).GetComponentInParent<PhotonView>();
			int num = (((Object)(object)val != (Object)null && val.ViewID > 0) ? val.ViewID : Mathf.Abs(((Object)box).GetInstanceID()));
			if (!_storedCandidatesByBox.TryGetValue(num, out Dictionary<int, CapturedValuable> value) || value.Count == 0)
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogInfo((object)$"[HaulOfFame/Hauler] Extracted box={num} had no individually tracked valuables.");
				}
				return;
			}
			foreach (KeyValuePair<int, CapturedValuable> item in value)
			{
				_candidates[item.Key] = item.Value;
				_capturedViewIds.Add(item.Key);
			}
			_logger.LogInfo((object)$"[HaulOfFame/Hauler] Extracted box={num}; promoted {value.Count} stored valuables into the final selection.");
		}

		public void HandleSceneChanged(Scene scene)
		{
			_announcement.Hide();
			_trophy.HandleSceneChanged();
			if (_config.DebugLogging.Value)
			{
				_logger.LogInfo((object)$"[HaulOfFame/Scene] Loaded {((Scene)(ref scene)).name}[{((Scene)(ref scene)).buildIndex}]; championPreserved={_champion != null}.");
			}
		}

		private void OnPrepareReceived(int viewId, int extractionPointViewId)
		{
			if (!_config.Enabled.Value || _capturedViewIds.Contains(viewId))
			{
				return;
			}
			try
			{
				PhotonView val = PhotonView.Find(viewId);
				PhysGrabObject val2 = (((Object)(object)val != (Object)null) ? (((Component)val).GetComponent<PhysGrabObject>() ?? ((Component)val).GetComponentInParent<PhysGrabObject>() ?? ((Component)val).GetComponentInChildren<PhysGrabObject>()) : null);
				ExtractionPoint val3 = _bindings.FindActiveExtractionPoint(extractionPointViewId);
				if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
				{
					_logger.LogWarning((object)$"[HaulOfFame/Capture] Could not resolve prepared valuable view={viewId}, extractionView={extractionPointViewId}.");
				}
				else
				{
					CaptureLocal(val3, val2, "host prepare event");
				}
			}
			catch (Exception ex)
			{
				_logger.LogWarning((object)$"[HaulOfFame/Capture] Prepared valuable view={viewId} failed: {ex.GetType().Name}: {ex.Message}");
			}
		}

		private void CaptureLocal(ExtractionPoint extractionPoint, PhysGrabObject physObject, string source)
		{
			if (!_bindings.TryCapture(extractionPoint, physObject, out CapturedValuable captured, out float localHaulScore, out string failure))
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogWarning((object)("[HaulOfFame/Capture] Ignored extraction target from " + source + ": " + failure + "."));
				}
			}
			else if (_capturedViewIds.Add(captured.ViewId))
			{
				_candidates[captured.ViewId] = captured;
				if (captured.Beats(_bestSnapshot?.Valuable) && TrophyModelSnapshot.TryCreate(captured, physObject, _logger, out TrophyModelSnapshot snapshot))
				{
					_bestSnapshot?.Dispose();
					_bestSnapshot = snapshot;
				}
				int actorNumber = ((PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null) ? PhotonNetwork.LocalPlayer.ActorNumber : 0);
				RecordContribution(actorNumber, captured.ViewId, localHaulScore);
				if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
				{
					_network.SendContribution(captured.ViewId, localHaulScore);
				}
				_logger.LogInfo((object)$"[HaulOfFame/Capture] Extracted '{captured.Name}', view={captured.ViewId}, value=${captured.CurrentValue:N0}/${captured.OriginalValue:N0}, localScore={localHaulScore:0.###}, source={source}, modelCopy={_bestSnapshot?.Valuable.ViewId == captured.ViewId}.");
			}
		}

		private void OnContributionReceived(int actorNumber, int viewId, float score)
		{
			if (!_candidates.ContainsKey(viewId) && !IsStoredCandidate(viewId))
			{
				if (_config.DebugLogging.Value)
				{
					_logger.LogWarning((object)$"[HaulOfFame/Network] Contribution arrived for unknown view={viewId} from actor={actorNumber}.");
				}
				return;
			}
			RecordContribution(actorNumber, viewId, score);
			if (_config.DebugLogging.Value)
			{
				_logger.LogInfo((object)$"[HaulOfFame/Network] Contribution accepted: actor={actorNumber}, view={viewId}, score={score:0.###}.");
			}
		}

		private void RecordContribution(int actorNumber, int viewId, float score)
		{
			score = Mathf.Clamp(score, 0f, 1000f);
			if (!_contributions.TryGetValue(viewId, out Dictionary<int, float> value))
			{
				value = new Dictionary<int, float>();
				_contributions[viewId] = value;
			}
			if (!value.TryGetValue(actorNumber, out var value2) || score > value2)
			{
				value[actorNumber] = score;
			}
		}

		private void FinalizeChampion()
		{
			CapturedValuable capturedValuable = null;
			foreach (CapturedValuable value2 in _candidates.Values)
			{
				if (value2.Beats(capturedValuable))
				{
					capturedValuable = value2;
				}
			}
			if (capturedValuable == null)
			{
				_logger.LogWarning((object)"[HaulOfFame/Result] Final extraction completed, but no valid valuable was captured.");
				return;
			}
			int[] array = Array.Empty<int>();
			float[] array2 = Array.Empty<float>();
			if (_contributions.TryGetValue(capturedValuable.ViewId, out Dictionary<int, float> value))
			{
				array = new int[value.Count];
				array2 = new float[value.Count];
				int num = 0;
				foreach (KeyValuePair<int, float> item in value)
				{
					array[num] = item.Key;
					array2[num] = item.Value;
					num++;
				}
			}
			bool flag = !PhotonNetwork.InRoom || _network.AllPlayersHaveMod();
			ChampionData champion = new ChampionData(capturedValuable, array, array2, flag);
			HandleChampion(champion);
			if (PhotonNetwork.InRoom)
			{
				_network.BroadcastChampion(champion);
			}
			_logger.LogInfo((object)$"[HaulOfFame/Result] Champion selected: '{capturedValuable.Name}', view={capturedValuable.ViewId}, value=${capturedValuable.CurrentValue:N0}, retained={capturedValuable.RetainedPercent:0.#}%, contributors={array.Length}, completeAttribution={flag}.");
		}

		private void OnChampionReceived(ChampionData champion)
		{
			if (_config.Enabled.Value)
			{
				HandleChampion(champion);
				_logger.LogInfo((object)$"[HaulOfFame/Network] Host champion received: '{champion.Valuable.Name}', view={champion.Valuable.ViewId}, value=${champion.Valuable.CurrentValue:N0}.");
			}
		}

		private void HandleChampion(ChampionData champion)
		{
			_champion = champion;
			(string, string, string, string) tuple = FormatChampion(champion);
			_announcement.Show(tuple.Item1, tuple.Item2, tuple.Item3);
			TrophyModelSnapshot snapshot = FindSnapshot(champion.Valuable.ViewId);
			_trophy.ShowChampion(champion, snapshot, tuple.Item4);
		}

		private (string Title, string Name, string Details, string Plaque) FormatChampion(ChampionData champion)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			bool isSpanish = _config.IsSpanish;
			string text = ColorUtility.ToHtmlStringRGB(_config.GetAccentColor());
			string item = (isSpanish ? "HAUL OF FAME — CAMPEÓN DE CARGA" : "HAUL OF FAME — HAUL CHAMPION");
			string text2 = "$" + champion.Valuable.CurrentValue.ToString("N0", CultureInfo.InvariantCulture);
			string text3 = champion.Valuable.RetainedPercent.ToString("0.#", CultureInfo.InvariantCulture) + "%";
			string item2 = (isSpanish ? (text2 + "  •  " + text3 + " CONSERVADO") : (text2 + "  •  " + text3 + " PRESERVED"));
			string text4 = FormatContributors(champion, isSpanish);
			string item3 = "<color=#" + text + ">HAUL OF FAME</color>\n" + champion.Valuable.Name.ToUpperInvariant() + "\n" + text2 + "  •  " + text3 + " " + (isSpanish ? "CONSERVADO" : "PRESERVED") + "\n" + text4;
			return (Title: item, Name: champion.Valuable.Name.ToUpperInvariant(), Details: item2, Plaque: item3);
		}

		private string FormatContributors(ChampionData champion, bool spanish)
		{
			List<(int, float)> list = new List<(int, float)>();
			float num = 0f;
			for (int i = 0; i < champion.ContributorActors.Length && i < champion.ContributorScores.Length; i++)
			{
				float num2 = Mathf.Max(0f, champion.ContributorScores[i]);
				if (!(num2 <= 0f))
				{
					list.Add((champion.ContributorActors[i], num2));
					num += num2;
				}
			}
			if (num <= 0f || list.Count == 0)
			{
				if (!spanish)
				{
					return "TRANSPORTED BY THE CREW";
				}
				return "TRANSPORTADO POR LA TRIPULACIÓN";
			}
			list.Sort(((int Actor, float Score) left, (int Actor, float Score) right) => right.Score.CompareTo(left.Score));
			int num3 = Mathf.Clamp(_config.MaxContributors.Value, 1, 8);
			float num4 = Mathf.Clamp(_config.MinimumContributionPercent.Value, 0f, 100f);
			List<string> list2 = new List<string>();
			foreach (var item in list)
			{
				if (list2.Count >= num3)
				{
					break;
				}
				float num5 = item.Item2 * 100f / num;
				if (!(num5 < num4))
				{
					list2.Add($"{_bindings.GetActorName(item.Item1).ToUpperInvariant()} {num5:0}%");
				}
			}
			string text = (spanish ? "MVP: " : "MVP: ") + ((list2.Count > 0) ? string.Join("  •  ", list2) : (spanish ? "TRIPULACIÓN" : "CREW"));
			if (!champion.AttributionComplete)
			{
				text += (spanish ? "  •  DATOS PARCIALES" : "  •  PARTIAL DATA");
			}
			return text;
		}

		private void BeginMission(Scene scene)
		{
			ResetAll("new mission scene");
			_missionSceneHandle = ((Scene)(ref scene)).handle;
			_logger.LogInfo((object)$"[HaulOfFame/Lifecycle] Mission tracking started in {((Scene)(ref scene)).name}[{((Scene)(ref scene)).buildIndex}].");
		}

		private void ResetAll(string reason)
		{
			_trophy.Clear();
			_announcement.Hide();
			_bestSnapshot?.Dispose();
			_bestSnapshot = null;
			foreach (TrophyModelSnapshot value in _storedBestSnapshotsByBox.Values)
			{
				value.Dispose();
			}
			_storedBestSnapshotsByBox.Clear();
			_champion = null;
			_candidates.Clear();
			_contributions.Clear();
			_storedCandidatesByBox.Clear();
			_capturedViewIds.Clear();
			_storedViewIds.Clear();
			_finalizationTime = -1f;
			_missionSceneHandle = int.MinValue;
			if (_config.DebugLogging.Value)
			{
				_logger.LogInfo((object)("[HaulOfFame/Lifecycle] Runtime state cleared: " + reason + "."));
			}
		}

		private void OnConfigChanged()
		{
			_announcement.ApplyConfig();
			_trophy.ApplyConfig();
			if (_champion != null)
			{
				(string, string, string, string) tuple = FormatChampion(_champion);
				TrophyModelSnapshot snapshot = FindSnapshot(_champion.Valuable.ViewId);
				_trophy.ShowChampion(_champion, snapshot, tuple.Item4);
			}
			_logger.LogInfo((object)"[HaulOfFame/Config] Configuration applied without restarting the game.");
		}

		private static bool IsAuthority()
		{
			if (PhotonNetwork.InRoom)
			{
				return PhotonNetwork.IsMasterClient;
			}
			return true;
		}

		private bool IsStoredCandidate(int viewId)
		{
			foreach (Dictionary<int, CapturedValuable> value in _storedCandidatesByBox.Values)
			{
				if (value.ContainsKey(viewId))
				{
					return true;
				}
			}
			return false;
		}

		private TrophyModelSnapshot? FindSnapshot(int viewId)
		{
			if (_bestSnapshot != null && _bestSnapshot.Valuable.ViewId == viewId)
			{
				return _bestSnapshot;
			}
			foreach (TrophyModelSnapshot value in _storedBestSnapshotsByBox.Values)
			{
				if (value.Valuable.ViewId == viewId)
				{
					return value;
				}
			}
			return null;
		}

		public void Dispose()
		{
			if (_disposed)
			{
				return;
			}
			_disposed = true;
			_config.Changed -= OnConfigChanged;
			_network.PrepareReceived -= OnPrepareReceived;
			_network.ContributionReceived -= OnContributionReceived;
			_network.ChampionReceived -= OnChampionReceived;
			_trophy.Clear();
			_bestSnapshot?.Dispose();
			_bestSnapshot = null;
			foreach (TrophyModelSnapshot value in _storedBestSnapshotsByBox.Values)
			{
				value.Dispose();
			}
			_storedBestSnapshotsByBox.Clear();
			_network.Dispose();
			_announcement.Dispose();
			_trophy.Dispose();
		}
	}
}
namespace HaulOfFame.Config
{
	public enum DisplayLanguage
	{
		Auto,
		English,
		Spanish
	}
	public enum TrophyPositionMode
	{
		FixedWorld,
		ScreenRelative
	}
	public sealed class ModConfig : IDisposable
	{
		private const float ExternalReloadInterval = 0.5f;

		private readonly ConfigFile _configFile;

		private readonly List<Action> _unsubscribeActions = new List<Action>();

		private DateTime _lastWriteTimeUtc;

		private long _lastFileLength;

		private float _reloadTimer;

		private bool _reloading;

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<bool> ShowAnnouncement { get; }

		public ConfigEntry<bool> ShowWorldTrophy { get; }

		public ConfigEntry<bool> ShowEmptyBase { get; }

		public ConfigEntry<float> AnnouncementDuration { get; }

		public ConfigEntry<int> MaxContributors { get; }

		public ConfigEntry<float> MinimumContributionPercent { get; }

		public ConfigEntry<DisplayLanguage> Language { get; }

		public ConfigEntry<float> TrophyScale { get; }

		public ConfigEntry<float> SpinSpeed { get; }

		public ConfigEntry<float> BobHeight { get; }

		public ConfigEntry<float> BobSpeed { get; }

		public ConfigEntry<TrophyPositionMode> PositionMode { get; }

		public ConfigEntry<float> WorldX { get; }

		public ConfigEntry<float> WorldY { get; }

		public ConfigEntry<float> WorldZ { get; }

		public ConfigEntry<float> OffsetX { get; }

		public ConfigEntry<float> OffsetY { get; }

		public ConfigEntry<float> OffsetZ { get; }

		public ConfigEntry<float> RotationY { get; }

		public ConfigEntry<string> AccentColor { get; }

		public ConfigEntry<bool> SoundEnabled { get; }

		public ConfigEntry<float> SoundVolume { get; }

		public ConfigEntry<bool> DebugLogging { get; }

		public bool IsSpanish
		{
			get
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Invalid comparison between Unknown and I4
				if (Language.Value != DisplayLanguage.Spanish)
				{
					if (Language.Value == DisplayLanguage.Auto)
					{
						return (int)Application.systemLanguage == 34;
					}
					return false;
				}
				return true;
			}
		}

		public event Action? Changed;

		public ModConfig(ConfigFile config)
		{
			_configFile = config;
			Enabled = Bind(config, "General", "Enabled", defaultValue: true, "Enable Haul of Fame.");
			ShowAnnouncement = Bind(config, "General", "ShowAnnouncement", defaultValue: true, "Show the post-extraction champion banner.");
			ShowWorldTrophy = Bind(config, "General", "ShowWorldTrophy", defaultValue: true, "Display the winning valuable as a harmless trophy near the truck screen.");
			ShowEmptyBase = Bind(config, "General", "ShowEmptyBase", defaultValue: true, "Keep the empty trophy pedestal visible in the truck before a champion is selected.");
			AnnouncementDuration = Bind(config, "General", "AnnouncementDuration", 5f, "Seconds the champion banner remains visible.");
			MaxContributors = Bind(config, "General", "MaxContributors", 4, "Maximum contributor names displayed on the trophy plaque.");
			MinimumContributionPercent = Bind(config, "General", "MinimumContributionPercent", 2f, "Hide contributors below this percentage.");
			Language = Bind(config, "General", "