Decompiled source of HowToFishSpeedrunMod v0.2.6

BepInEx/plugins/HowToFish.SpeedrunMod/HowToFish.SpeedrunMod.dll

Decompiled 8 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.Security.Cryptography;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using HowToFish.SpeedrunMod.Configuration;
using HowToFish.SpeedrunMod.Core;
using HowToFish.SpeedrunMod.Game;
using HowToFish.SpeedrunMod.UI;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace HowToFish.SpeedrunMod
{
	[BepInPlugin("community.howtofish.speedrunmod", "How to Fish Speedrun Mod", "0.2.6")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "community.howtofish.speedrunmod";

		public const string PluginName = "How to Fish Speedrun Mod";

		public const string PluginVersion = "0.2.6";

		private ModConfig _config;

		private RunClock _clock;

		private SplitStateMachine _splits;

		private GameTelemetry _telemetry;

		private SpeedrunHud _hud;

		private FinalResultUI _finalUI;

		private Harmony _harmony;

		private RunState _state;

		private FinishedRunResult _finished;

		private bool _manualHudVisible = true;

		private bool _lastMenu;

		private bool _lastLoading;

		private TimeSpan Elapsed
		{
			get
			{
				if (!UseLoadless)
				{
					return _clock.Rta;
				}
				return _clock.Loadless;
			}
		}

		private bool UseLoadless => string.Equals(_config.TimingMethod, "Loadless", StringComparison.OrdinalIgnoreCase);

		private void Awake()
		{
			string text = Path.Combine(Paths.ConfigPath, "HowToFish.Speedrun");
			Directory.CreateDirectory(text);
			string path = Path.Combine(text, "any-percent.json");
			_config = ModConfig.Load(path);
			_config.Bind((BaseUnityPlugin)(object)this);
			_clock = new RunClock(new StopwatchTickSource());
			_splits = new SplitStateMachine(_config.Splits);
			_telemetry = new GameTelemetry();
			_hud = new SpeedrunHud(_config);
			_hud.Create();
			_finalUI = new FinalResultUI();
			GameSignals.FinalAcceptedImmediate = (Action)Delegate.Combine(GameSignals.FinalAcceptedImmediate, new Action(FinishRun));
			InstallReadOnlyHooks();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"READ-ONLY GAME TELEMETRY — NO GAMEPLAY STATE MODIFICATION");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Game version " + Application.version + ", executable SHA256 " + ExecutableHash()));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Progression detector: DISCOVERED/INSTRUMENTED (5 production islands; level6 is dev island).");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Final flow: INSTRUMENTED — requires user validation before leaderboard release.");
		}

		private void Update()
		{
			//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)
			KeyboardShortcut toggleHud = _config.ToggleHud;
			if (((KeyboardShortcut)(ref toggleHud)).IsDown())
			{
				_manualHudVisible = !_manualHudVisible;
			}
			if (UnityInput.Current.GetKeyDown((KeyCode)290))
			{
				ResetRun("manual-emergency");
			}
			SignalBatch signalBatch = GameSignals.Consume();
			GameSnapshot gameSnapshot = _telemetry.Read();
			LogLoadingEdge(gameSnapshot);
			if (signalBatch.NewGameRequested)
			{
				ResetRun("new-game-created");
				_state = RunState.PendingStart;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"NEW_GAME_PENDING first playable frame");
			}
			if (signalBatch.SaveSelected)
			{
				ResetRun("different-save-loaded");
				_state = RunState.Inactive;
			}
			if (_state == RunState.PendingStart && gameSnapshot.PlayerReady && !gameSnapshot.InMainMenu && !gameSnapshot.Loading)
			{
				_splits.Reset();
				_clock.Start();
				_telemetry.ResetBaseline(gameSnapshot);
				_state = RunState.Running;
				((BaseUnityPlugin)this).Logger.LogInfo((object)"RUN_START first playable frame");
			}
			if (_state == RunState.Running)
			{
				_clock.SetLoading(gameSnapshot.Loading);
				if (!string.IsNullOrEmpty(signalBatch.BossKilled))
				{
					LogEvent("BossKilled", signalBatch.BossKilled);
				}
				if (signalBatch.BoatUnlocked)
				{
					OnEvent("BoatUnlocked", null);
				}
				if (signalBatch.IslandUnlocked >= 0)
				{
					OnEvent("IslandUnlocked", signalBatch.IslandUnlocked.ToString());
				}
				if (signalBatch.FinalKeysAcquired)
				{
					OnEvent("FinalKeysAcquired", null);
				}
				if (signalBatch.FinalInteractionDispatched)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"FINAL_INTERACTION_DISPATCHED (instrumentation; not timing finish)");
				}
				if (signalBatch.FinalAccepted)
				{
					FinishRun();
				}
				_telemetry.EmitEdges(gameSnapshot, LogEvent);
				if (!_lastMenu && gameSnapshot.InMainMenu)
				{
					ResetRun("returned-to-main-menu");
				}
			}
			else
			{
				_telemetry.EmitEdges(gameSnapshot, LogEvent);
			}
			if (_state == RunState.Finished && gameSnapshot.InMainMenu)
			{
				_finalUI.Clear();
				_finished = null;
				_state = RunState.Inactive;
				_clock.Reset();
				_splits.Reset();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"FINAL_RESULT_CLEARED main-menu");
			}
			_lastMenu = gameSnapshot.InMainMenu;
			_finalUI.Tick(gameSnapshot.InMainMenu);
			bool flag = _state == RunState.Running && _config.HudEnabled && _manualHudVisible && !gameSnapshot.InMainMenu && !gameSnapshot.Loading && !EndGameUI.IsShowingEndGame;
			_hud.Visible = flag;
			if (flag)
			{
				_hud.Render(_config.Category, Elapsed, _splits);
			}
		}

		private void OnEvent(string eventName, string value)
		{
			CompletedSplit completedSplit = _splits.Handle(eventName, value, Elapsed);
			if (completedSplit != null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("SPLIT " + completedSplit.Name + " segment=" + RunClock.Format(completedSplit.Segment) + " cumulative=" + RunClock.Format(completedSplit.Cumulative)));
			}
			else
			{
				LogEvent(eventName, value);
			}
		}

		private void LogEvent(string eventName, string value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("EVENT " + eventName + (string.IsNullOrEmpty(value) ? string.Empty : (" value=" + value))));
		}

		private void FinishRun()
		{
			if (_state == RunState.Running)
			{
				_clock.Stop();
				TimeSpan elapsed = Elapsed;
				CompletedSplit completedSplit = _splits.Handle("RunCompleted", null, elapsed);
				if (completedSplit != null)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("SPLIT " + completedSplit.Name + " segment=" + RunClock.Format(completedSplit.Segment) + " cumulative=" + RunClock.Format(completedSplit.Cumulative)));
				}
				_finished = new FinishedRunResult
				{
					Category = _config.Category,
					TimingMethod = _config.TimingMethod,
					TotalTime = elapsed,
					FinalSegmentTime = (completedSplit?.Segment ?? TimeSpan.Zero),
					CompletionTimestampUtc = DateTime.UtcNow,
					GameVersion = Application.version,
					Splits = new List<CompletedSplit>(_splits.Completed)
				};
				_state = RunState.Finished;
				_hud.Visible = false;
				_finalUI.SetResult(_finished);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("RUN_COMPLETE_ACCEPTED frozen=" + RunClock.Format(elapsed) + " detector=INSTRUMENTED"));
				SaveRun(_finished);
			}
		}

		private void ResetRun(string reason)
		{
			if (_clock != null && (_clock.Active || _clock.Finished))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("RUN_RESET " + reason + " at " + RunClock.Format(_clock.Rta)));
			}
			if (_clock != null)
			{
				_clock.Reset();
			}
			if (_splits != null)
			{
				_splits.Reset();
			}
			if (_finalUI != null)
			{
				_finalUI.Clear();
			}
			_finished = null;
			_state = RunState.Inactive;
		}

		private void InstallReadOnlyHooks()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_harmony = new Harmony("community.howtofish.speedrunmod");
			PatchPostfix(typeof(SaveManager), "CreateServer", "NewGamePostfix");
			PatchPostfix(typeof(SaveManager), "SelectServer", "SelectSavePostfix");
			PatchPrefix(typeof(BossManager), "OnBossDeath", "BossDeathPrefix");
			PatchPostfix(typeof(Boat), "UnlockBoat", "BoatUnlockedPostfix");
			PatchPrefix(typeof(OnlineIslandManager), "UnlockIsland", "UnlockIslandPrefix");
			PatchPostfix(typeof(NPCManager), "SetFinalBossKilled", "FinalKeysPostfix");
			PatchPostfix(typeof(EndGameInteractable), "Interact", "FinalInteractionPostfix");
			PatchPrefix(typeof(EndGameManager), "FinishGame", "FinalAcceptedPrefix");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Read-only observer hooks installed; Tutorial split/hook removed.");
		}

		private void PatchPostfix(Type targetType, string targetName, string hookName)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(targetType, targetName, (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(GameHooks), hookName, (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				throw new MissingMethodException(targetType.FullName, targetName);
			}
			_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private void PatchPrefix(Type targetType, string targetName, string hookName)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(targetType, targetName, (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(GameHooks), hookName, (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				throw new MissingMethodException(targetType.FullName, targetName);
			}
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private void LogLoadingEdge(GameSnapshot snapshot)
		{
			if (snapshot.Loading != _lastLoading)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)(snapshot.Loading ? "LOADING_STARTED" : "LOADING_ENDED"));
			}
			_lastLoading = snapshot.Loading;
		}

		private void SaveRun(FinishedRunResult result)
		{
			try
			{
				string text = Path.Combine(Paths.ConfigPath, "HowToFish.Speedrun", "runs");
				Directory.CreateDirectory(text);
				string path = Path.Combine(text, result.CompletionTimestampUtc.ToString("yyyyMMdd-HHmmss") + ".json");
				File.WriteAllText(path, JsonConvert.SerializeObject((object)new
				{
					category = result.Category,
					timingMethod = result.TimingMethod,
					duration = result.TotalTime.TotalMilliseconds,
					finalSegment = result.FinalSegmentTime.TotalMilliseconds,
					completedAtUtc = result.CompletionTimestampUtc,
					gameVersion = result.GameVersion,
					toolVersion = "0.2.6",
					executableSha256 = ExecutableHash(),
					splits = result.Splits,
					detectorStatus = "INSTRUMENTED"
				}, (Formatting)1));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Unable to save run record: " + ex.Message));
			}
		}

		private static string ExecutableHash()
		{
			try
			{
				string path = Path.Combine(Paths.GameRootPath, "How to Fish.exe");
				using SHA256 sHA = SHA256.Create();
				using FileStream inputStream = File.OpenRead(path);
				return BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", string.Empty);
			}
			catch
			{
				return "unavailable";
			}
		}

		private void OnDestroy()
		{
			GameSignals.FinalAcceptedImmediate = (Action)Delegate.Remove(GameSignals.FinalAcceptedImmediate, new Action(FinishRun));
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
}
namespace HowToFish.SpeedrunMod.Configuration
{
	public enum HudPosition
	{
		TopRight,
		TopLeft,
		BottomRight,
		BottomLeft
	}
	public sealed class ModConfig
	{
		public int SchemaVersion = 5;

		public List<SplitDefinition> Splits = new List<SplitDefinition>();

		private ConfigEntry<string> _category;

		private ConfigEntry<string> _timingMethod;

		private ConfigEntry<bool> _hudEnabled;

		private ConfigEntry<float> _scale;

		private ConfigEntry<HudPosition> _position;

		private ConfigEntry<float> _opacity;

		private ConfigEntry<int> _visibleSplits;

		private ConfigEntry<bool> _showCategory;

		private ConfigEntry<bool> _showMilliseconds;

		private ConfigEntry<KeyboardShortcut> _toggleHud;

		public string Category => _category.Value;

		public string TimingMethod => _timingMethod.Value;

		public bool HudEnabled => _hudEnabled.Value;

		public float Scale => _scale.Value;

		public HudPosition Position => _position.Value;

		public float Opacity => _opacity.Value;

		public int MaxVisibleRows => _visibleSplits.Value;

		public bool ShowCategory => _showCategory.Value;

		public bool ShowMilliseconds => _showMilliseconds.Value;

		public KeyboardShortcut ToggleHud => _toggleHud.Value;

		public float RightMargin => 32f;

		public float TopMargin => 28f;

		public float Width => 370f;

		public void Bind(BaseUnityPlugin plugin)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			_category = plugin.Config.Bind<string>("Run", "Category", "Any%", new ConfigDescription("Category label recorded with the run.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Any%", "100%" }), new object[0]));
			_timingMethod = plugin.Config.Bind<string>("Timer", "TimingMethod", "Loadless", new ConfigDescription("Timer shown by the HUD.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Loadless", "RTA" }), new object[0]));
			_hudEnabled = plugin.Config.Bind<bool>("HUD", "Enabled", true, "Show the in-game speedrun HUD.");
			_scale = plugin.Config.Bind<float>("HUD", "Scale", 1f, new ConfigDescription("HUD scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.6f, 1.8f), new object[0]));
			_position = plugin.Config.Bind<HudPosition>("HUD", "Position", HudPosition.TopRight, "Screen anchor for the HUD.");
			_opacity = plugin.Config.Bind<float>("HUD", "Opacity", 1f, new ConfigDescription("HUD text opacity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 1f), new object[0]));
			_visibleSplits = plugin.Config.Bind<int>("HUD", "VisibleSplits", 6, new ConfigDescription("Maximum visible split rows.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 12), new object[0]));
			_showCategory = plugin.Config.Bind<bool>("HUD", "ShowCategory", true, "Show the category name.");
			_showMilliseconds = plugin.Config.Bind<bool>("HUD", "ShowMilliseconds", true, "Show milliseconds in timer values.");
			_toggleHud = plugin.Config.Bind<KeyboardShortcut>("Hotkeys", "ToggleHUD", new KeyboardShortcut((KeyCode)289, (KeyCode[])(object)new KeyCode[0]), "Toggle the gameplay HUD. Settings remain available through Mod Menu when installed.");
		}

		public static ModConfig Load(string path)
		{
			ModConfig modConfig = null;
			if (File.Exists(path))
			{
				modConfig = JsonConvert.DeserializeObject<ModConfig>(File.ReadAllText(path));
			}
			if (modConfig == null || modConfig.SchemaVersion < 5 || modConfig.Splits == null || modConfig.Splits.Exists((SplitDefinition s) => string.Equals(s.Event, "TutorialComplete", StringComparison.OrdinalIgnoreCase)))
			{
				modConfig = CreateDefault();
				Directory.CreateDirectory(Path.GetDirectoryName(path));
				File.WriteAllText(path, JsonConvert.SerializeObject((object)modConfig, (Formatting)1));
			}
			return modConfig;
		}

		public static ModConfig CreateDefault()
		{
			ModConfig modConfig = new ModConfig();
			modConfig.Splits.Add(new SplitDefinition
			{
				Name = "Island 1",
				Event = "BoatUnlocked"
			});
			modConfig.Splits.Add(new SplitDefinition
			{
				Name = "Island 2",
				Event = "IslandUnlocked",
				Value = "3"
			});
			modConfig.Splits.Add(new SplitDefinition
			{
				Name = "Island 3",
				Event = "IslandUnlocked",
				Value = "4"
			});
			modConfig.Splits.Add(new SplitDefinition
			{
				Name = "Island 4",
				Event = "IslandUnlocked",
				Value = "5"
			});
			modConfig.Splits.Add(new SplitDefinition
			{
				Name = "Final Island",
				Event = "FinalKeysAcquired"
			});
			modConfig.Splits.Add(new SplitDefinition
			{
				Name = "Game Completion",
				Event = "RunCompleted"
			});
			return modConfig;
		}
	}
}
namespace HowToFish.SpeedrunMod.Core
{
	internal enum RunState
	{
		Inactive,
		PendingStart,
		Running,
		Finished
	}
	internal sealed class FinishedRunResult
	{
		internal string Category;

		internal string TimingMethod;

		internal TimeSpan TotalTime;

		internal TimeSpan FinalSegmentTime;

		internal DateTime CompletionTimestampUtc;

		internal string GameVersion;

		internal List<CompletedSplit> Splits;
	}
	public interface ITickSource
	{
		long Frequency { get; }

		long Timestamp { get; }
	}
	public sealed class StopwatchTickSource : ITickSource
	{
		public long Frequency => Stopwatch.Frequency;

		public long Timestamp => Stopwatch.GetTimestamp();
	}
	public sealed class RunClock
	{
		private readonly ITickSource _ticks;

		private long _startTick;

		private long _excludedTicks;

		private long _loadingStartTick;

		private long _stopTick;

		public bool Active { get; private set; }

		public bool Finished { get; private set; }

		public bool Loading { get; private set; }

		public TimeSpan Rta
		{
			get
			{
				if (!Active && !Finished)
				{
					return TimeSpan.Zero;
				}
				return ToTimeSpan((Finished ? _stopTick : _ticks.Timestamp) - _startTick);
			}
		}

		public TimeSpan Loadless
		{
			get
			{
				if (!Active && !Finished)
				{
					return TimeSpan.Zero;
				}
				long num = (Finished ? _stopTick : _ticks.Timestamp);
				long num2 = (Loading ? (num - _loadingStartTick) : 0);
				return ToTimeSpan(num - _startTick - _excludedTicks - num2);
			}
		}

		public RunClock(ITickSource ticks)
		{
			_ticks = ticks;
		}

		public void Start()
		{
			_startTick = _ticks.Timestamp;
			_excludedTicks = 0L;
			_loadingStartTick = 0L;
			Loading = false;
			Active = true;
			Finished = false;
			_stopTick = 0L;
		}

		public void Stop()
		{
			if (Active)
			{
				_stopTick = _ticks.Timestamp;
				if (Loading && _loadingStartTick != 0)
				{
					_excludedTicks += _stopTick - _loadingStartTick;
				}
				Loading = false;
				_loadingStartTick = 0L;
				Active = false;
				Finished = true;
			}
		}

		public void Reset()
		{
			Active = false;
			Loading = false;
			_startTick = 0L;
			_excludedTicks = 0L;
			_loadingStartTick = 0L;
			_stopTick = 0L;
			Finished = false;
		}

		public void SetLoading(bool loading)
		{
			if (Active && loading != Loading)
			{
				long timestamp = _ticks.Timestamp;
				if (loading)
				{
					_loadingStartTick = timestamp;
				}
				else if (_loadingStartTick != 0)
				{
					_excludedTicks += timestamp - _loadingStartTick;
				}
				Loading = loading;
				if (!loading)
				{
					_loadingStartTick = 0L;
				}
			}
		}

		private TimeSpan ToTimeSpan(long ticks)
		{
			return TimeSpan.FromSeconds((double)Math.Max(0L, ticks) / (double)_ticks.Frequency);
		}

		public static string Format(TimeSpan value)
		{
			if (value.TotalHours >= 1.0)
			{
				return string.Format(CultureInfo.InvariantCulture, "{0}:{1:00}:{2:00}.{3:000}", (int)value.TotalHours, value.Minutes, value.Seconds, value.Milliseconds);
			}
			return string.Format(CultureInfo.InvariantCulture, "{0:00}:{1:00}.{2:000}", (int)value.TotalMinutes, value.Seconds, value.Milliseconds);
		}
	}
	public sealed class SplitDefinition
	{
		public string Name;

		public string Event;

		public string Value;
	}
	public sealed class CompletedSplit
	{
		public string Name;

		public TimeSpan Segment;

		public TimeSpan Cumulative;
	}
	public sealed class SplitStateMachine
	{
		private readonly IList<SplitDefinition> _definitions;

		private readonly List<CompletedSplit> _completed = new List<CompletedSplit>();

		private TimeSpan _segmentStart;

		public IList<CompletedSplit> Completed => _completed.AsReadOnly();

		public int CurrentIndex { get; private set; }

		public bool Finished => CurrentIndex >= _definitions.Count;

		public SplitDefinition Current
		{
			get
			{
				if (!Finished)
				{
					return _definitions[CurrentIndex];
				}
				return null;
			}
		}

		public SplitStateMachine(IList<SplitDefinition> definitions)
		{
			_definitions = definitions ?? new List<SplitDefinition>();
		}

		public void Reset()
		{
			_completed.Clear();
			CurrentIndex = 0;
			_segmentStart = TimeSpan.Zero;
		}

		public CompletedSplit Handle(string eventName, string value, TimeSpan elapsed)
		{
			SplitDefinition current = Current;
			if (current == null || !Matches(current, eventName, value))
			{
				return null;
			}
			CompletedSplit completedSplit = new CompletedSplit();
			completedSplit.Name = current.Name;
			completedSplit.Cumulative = elapsed;
			completedSplit.Segment = elapsed - _segmentStart;
			_segmentStart = elapsed;
			_completed.Add(completedSplit);
			CurrentIndex++;
			return completedSplit;
		}

		public TimeSpan CurrentSegment(TimeSpan elapsed)
		{
			return elapsed - _segmentStart;
		}

		private static bool Matches(SplitDefinition definition, string eventName, string value)
		{
			if (!string.Equals(definition.Event, eventName, StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			if (!string.IsNullOrEmpty(definition.Value))
			{
				return string.Equals(definition.Value, value, StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}
	}
}
namespace HowToFish.SpeedrunMod.Game
{
	internal sealed class SignalBatch
	{
		internal bool NewGameRequested;

		internal bool SaveSelected;

		internal string BossKilled;

		internal bool BoatUnlocked;

		internal int IslandUnlocked = -1;

		internal bool FinalKeysAcquired;

		internal bool FinalInteractionDispatched;

		internal bool FinalAccepted;
	}
	internal static class GameSignals
	{
		internal static bool NewGameRequested;

		internal static bool SaveSelected;

		internal static string BossKilled;

		internal static bool BoatUnlocked;

		internal static int IslandUnlocked = -1;

		internal static bool FinalKeysAcquired;

		internal static bool FinalInteractionDispatched;

		internal static bool FinalAccepted;

		internal static Action FinalAcceptedImmediate;

		internal static SignalBatch Consume()
		{
			SignalBatch signalBatch = new SignalBatch();
			signalBatch.NewGameRequested = NewGameRequested;
			signalBatch.SaveSelected = SaveSelected;
			signalBatch.BossKilled = BossKilled;
			signalBatch.BoatUnlocked = BoatUnlocked;
			signalBatch.IslandUnlocked = IslandUnlocked;
			signalBatch.FinalKeysAcquired = FinalKeysAcquired;
			signalBatch.FinalInteractionDispatched = FinalInteractionDispatched;
			signalBatch.FinalAccepted = FinalAccepted;
			SignalBatch result = signalBatch;
			NewGameRequested = false;
			SaveSelected = false;
			BossKilled = null;
			BoatUnlocked = false;
			IslandUnlocked = -1;
			FinalKeysAcquired = false;
			FinalInteractionDispatched = false;
			FinalAccepted = false;
			return result;
		}
	}
	internal static class GameHooks
	{
		internal static void NewGamePostfix()
		{
			GameSignals.NewGameRequested = true;
		}

		internal static void SelectSavePostfix()
		{
			GameSignals.SaveSelected = true;
		}

		internal static void BossDeathPrefix()
		{
			try
			{
				Creature boss = BossManager.Boss;
				GameSignals.BossKilled = (((Object)(object)boss == (Object)null) ? "UnknownBoss" : ((object)boss).GetType().Name);
			}
			catch
			{
				GameSignals.BossKilled = "UnknownBoss";
			}
		}

		internal static void UnlockIslandPrefix(byte islandIndex)
		{
			try
			{
				if (islandIndex > OnlineIslandManager.MaxIslandUnlocked)
				{
					GameSignals.IslandUnlocked = islandIndex;
				}
			}
			catch
			{
				GameSignals.IslandUnlocked = islandIndex;
			}
		}

		internal static void BoatUnlockedPostfix(Boat __instance)
		{
			if ((Object)(object)__instance != (Object)null && __instance.BoatUnlocked)
			{
				GameSignals.BoatUnlocked = true;
			}
		}

		internal static void FinalKeysPostfix()
		{
			GameSignals.FinalKeysAcquired = true;
		}

		internal static void FinalInteractionPostfix()
		{
			GameSignals.FinalInteractionDispatched = true;
		}

		internal static void FinalAcceptedPrefix()
		{
			GameSignals.FinalAccepted = true;
			GameSignals.FinalAcceptedImmediate?.Invoke();
		}
	}
	internal sealed class GameSnapshot
	{
		internal bool PlayerReady;

		internal bool InMainMenu;

		internal bool Loading;

		internal byte Island;

		internal bool Finished;
	}
	internal sealed class GameTelemetry
	{
		private bool _initialized;

		private GameSnapshot _last;

		internal GameSnapshot Read()
		{
			GameSnapshot gameSnapshot = new GameSnapshot();
			Player localPlayer = Player.LocalPlayer;
			gameSnapshot.PlayerReady = (Object)(object)localPlayer != (Object)null && Player.LocalPlayerEnabled;
			gameSnapshot.InMainMenu = MainMenuManager.IsInMenu;
			gameSnapshot.Loading = IslandManager.IsLoading || ReadPrivateStaticBool(typeof(LoadingManager), "_isShowingLoading");
			gameSnapshot.Island = (byte)((!((Object)(object)OnlineIslandManager.Instance == (Object)null)) ? OnlineIslandManager.CurIsland : 0);
			gameSnapshot.Finished = (Object)(object)EndGameManager.Instance != (Object)null && EndGameManager.Instance.HasFinishedGame;
			return gameSnapshot;
		}

		internal void EmitEdges(GameSnapshot current, Action<string, string> emit)
		{
			if (!_initialized)
			{
				_initialized = true;
				_last = current;
				return;
			}
			if (_last.Island != current.Island)
			{
				emit("IslandEntered", current.Island.ToString());
			}
			if (!_last.Finished && current.Finished)
			{
				emit("CompletionStateObserved", null);
			}
			_last = current;
		}

		internal void ResetBaseline(GameSnapshot current)
		{
			_initialized = true;
			_last = current;
		}

		private static bool ReadPrivateStaticBool(Type type, string fieldName)
		{
			try
			{
				FieldInfo field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic);
				return field != null && (bool)field.GetValue(null);
			}
			catch
			{
				return false;
			}
		}
	}
}
namespace HowToFish.SpeedrunMod.UI
{
	internal sealed class FinalResultUI
	{
		private GameObject _root;

		private FinishedRunResult _result;

		internal void SetResult(FinishedRunResult result)
		{
			_result = result;
		}

		internal void Tick(bool inMainMenu)
		{
			if (inMainMenu)
			{
				Clear();
				return;
			}
			if (_result == null || !EndGameUI.IsShowingEndGame)
			{
				Hide();
				return;
			}
			EndGameUI val = FindEndGameUI();
			if ((Object)(object)val == (Object)null)
			{
				Hide();
				return;
			}
			RectTransform val2 = ReadField<RectTransform>(val, "_creditsHolder");
			GameObject val3 = ReadField<GameObject>(val, "_endGameCanvas");
			if ((Object)(object)val3 == (Object)null || !val3.activeInHierarchy || (Object)(object)val2 == (Object)null)
			{
				Hide();
				return;
			}
			if ((Object)(object)_root == (Object)null)
			{
				Create(val3.transform, val2);
			}
			_root.transform.SetAsLastSibling();
			_root.SetActive(true);
		}

		internal void Clear()
		{
			_result = null;
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
		}

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

		private void Create(Transform parent, RectTransform credits)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0044: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject("SpeedrunFinalResult", new Type[1] { typeof(RectTransform) });
			RectTransform component = _root.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = new Vector2(0.5f, 0.7f);
			component.anchorMax = new Vector2(0.5f, 0.7f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(720f, 180f);
			TextMeshProUGUI native = null;
			TextMeshProUGUI[] componentsInChildren = ((Component)credits).GetComponentsInChildren<TextMeshProUGUI>(true);
			if (componentsInChildren.Length > 0)
			{
				native = componentsInChildren[0];
			}
			CreateText("Label", (Transform)(object)component, "TIME", 34f, new Vector2(0f, 42f), native);
			CreateText("Value", (Transform)(object)component, RunClock.Format(_result.TotalTime), 58f, new Vector2(0f, -28f), native);
		}

		private static void CreateText(string name, Transform parent, string value, float size, Vector2 position, TextMeshProUGUI native)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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(TextMeshProUGUI)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 anchorMin = (component.anchorMax = new Vector2(0.5f, 0.5f));
			component.anchorMin = anchorMin;
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = position;
			component.sizeDelta = new Vector2(700f, 68f);
			TextMeshProUGUI component2 = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component2).text = value;
			((TMP_Text)component2).fontSize = size;
			((TMP_Text)component2).alignment = (TextAlignmentOptions)514;
			((Graphic)component2).raycastTarget = false;
			if ((Object)(object)native != (Object)null)
			{
				((TMP_Text)component2).font = ((TMP_Text)native).font;
				((TMP_Text)component2).fontSharedMaterial = ((TMP_Text)native).fontSharedMaterial;
				((Graphic)component2).color = ((Graphic)native).color;
				((TMP_Text)component2).outlineColor = ((TMP_Text)native).outlineColor;
				((TMP_Text)component2).outlineWidth = ((TMP_Text)native).outlineWidth;
			}
		}

		private static EndGameUI FindEndGameUI()
		{
			FieldInfo field = typeof(EndGameUI).GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic);
			if (!(field == null))
			{
				object? value = field.GetValue(null);
				return (EndGameUI)((value is EndGameUI) ? value : null);
			}
			return null;
		}

		private static T ReadField<T>(object instance, string name) where T : class
		{
			FieldInfo field = instance.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
			if (!(field == null))
			{
				return field.GetValue(instance) as T;
			}
			return null;
		}
	}
	internal sealed class SpeedrunHud
	{
		private readonly ModConfig _config;

		private GameObject _root;

		private TextMeshProUGUI _category;

		private TextMeshProUGUI _timer;

		private RectTransform _rowsRoot;

		private RectTransform _panel;

		private readonly List<TextMeshProUGUI> _names = new List<TextMeshProUGUI>();

		private readonly List<TextMeshProUGUI> _times = new List<TextMeshProUGUI>();

		private TMP_FontAsset _font;

		private TMP_FontAsset _backdropFont;

		private Material _sharedMaterial;

		internal bool Visible
		{
			get
			{
				if ((Object)(object)_root != (Object)null)
				{
					return _root.activeSelf;
				}
				return false;
			}
			set
			{
				if ((Object)(object)_root != (Object)null)
				{
					_root.SetActive(value);
				}
			}
		}

		internal SpeedrunHud(ModConfig config)
		{
			_config = config;
		}

		internal void Create()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			_root = new GameObject("SpeedrunHUD", new Type[3]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler)
			});
			Object.DontDestroyOnLoad((Object)(object)_root);
			Canvas component = _root.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 32760;
			CanvasScaler component2 = _root.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.screenMatchMode = (ScreenMatchMode)0;
			component2.matchWidthOrHeight = 0.5f;
			_panel = CreateRect("Anchor", _root.transform);
			_panel.anchorMin = new Vector2(1f, 1f);
			_panel.anchorMax = new Vector2(1f, 1f);
			_panel.pivot = new Vector2(1f, 1f);
			_panel.anchoredPosition = new Vector2(0f - _config.RightMargin, 0f - _config.TopMargin);
			_panel.sizeDelta = new Vector2(_config.Width, 480f);
			_category = CreateText("Category", (Transform)(object)_panel, 25f, (FontStyles)32, (TextAlignmentOptions)260);
			SetRect(((TMP_Text)_category).rectTransform, 0f, -2f, _config.Width, 34f);
			_timer = CreateText("Timer", (Transform)(object)_panel, 43f, (FontStyles)0, (TextAlignmentOptions)260);
			SetRect(((TMP_Text)_timer).rectTransform, 0f, -36f, _config.Width, 58f);
			_rowsRoot = CreateRect("Segments", (Transform)(object)_panel);
			SetRect(_rowsRoot, 0f, -104f, _config.Width, 370f);
			for (int i = 0; i < 12; i++)
			{
				TextMeshProUGUI val = CreateText("SegmentName" + i, (Transform)(object)_rowsRoot, 22f, (FontStyles)0, (TextAlignmentOptions)4097);
				TextMeshProUGUI val2 = CreateText("SegmentTime" + i, (Transform)(object)_rowsRoot, 22f, (FontStyles)0, (TextAlignmentOptions)4100);
				SetRect(((TMP_Text)val).rectTransform, -155f, (float)(-i) * 31f, _config.Width - 155f, 30f);
				SetRect(((TMP_Text)val2).rectTransform, 0f, (float)(-i) * 31f, 150f, 30f);
				_names.Add(val);
				_times.Add(val2);
			}
			ApplyNativeStyleWhenAvailable();
		}

		internal void Render(string category, TimeSpan elapsed, SplitStateMachine splits)
		{
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			if ((Object)(object)_font == (Object)null)
			{
				ApplyNativeStyleWhenAvailable();
			}
			ApplyLiveSettings();
			((Component)_category).gameObject.SetActive(_config.ShowCategory);
			((TMP_Text)_category).text = (category ?? "Any%").ToUpperInvariant();
			((TMP_Text)_timer).text = Format(elapsed);
			int num = Math.Max(1, Math.Min(_names.Count, _config.MaxVisibleRows));
			int currentIndex = splits.CurrentIndex;
			int num2 = Math.Max(0, currentIndex - Math.Max(0, num - 2));
			IList<CompletedSplit> completed = splits.Completed;
			for (int i = 0; i < num; i++)
			{
				int num3 = num2 + i;
				if (num3 < completed.Count)
				{
					((TMP_Text)_names[i]).text = completed[num3].Name;
					((TMP_Text)_times[i]).text = Format(completed[num3].Segment);
					SetActiveStyle(i, active: false);
				}
				else if (num3 == currentIndex && splits.Current != null)
				{
					((TMP_Text)_names[i]).text = splits.Current.Name;
					((TMP_Text)_times[i]).text = Format(splits.CurrentSegment(elapsed));
					SetActiveStyle(i, active: true);
				}
				else
				{
					((TMP_Text)_names[i]).text = string.Empty;
					((TMP_Text)_times[i]).text = string.Empty;
					SetActiveStyle(i, active: false);
				}
			}
			for (int j = num; j < _names.Count; j++)
			{
				((TMP_Text)_names[j]).text = string.Empty;
				((TMP_Text)_times[j]).text = string.Empty;
				((Component)_names[j]).gameObject.SetActive(false);
				((Component)_times[j]).gameObject.SetActive(false);
			}
		}

		private string Format(TimeSpan value)
		{
			string text = RunClock.Format(value);
			if (!_config.ShowMilliseconds)
			{
				return text.Substring(0, text.Length - 4);
			}
			return text;
		}

		private void ApplyLiveSettings()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			((Transform)_panel).localScale = Vector3.one * _config.Scale;
			bool flag = _config.Position == HudPosition.TopLeft || _config.Position == HudPosition.BottomLeft;
			bool flag2 = _config.Position == HudPosition.TopLeft || _config.Position == HudPosition.TopRight;
			RectTransform panel = _panel;
			Vector2 anchorMin = (_panel.anchorMax = new Vector2(flag ? 0f : 1f, flag2 ? 1f : 0f));
			panel.anchorMin = anchorMin;
			_panel.pivot = new Vector2(flag ? 0f : 1f, flag2 ? 1f : 0f);
			_panel.anchoredPosition = new Vector2(flag ? _config.RightMargin : (0f - _config.RightMargin), flag2 ? (0f - _config.TopMargin) : _config.TopMargin);
			foreach (TextMeshProUGUI item in AllTexts())
			{
				Color color = ((Graphic)item).color;
				color.a = _config.Opacity;
				((Graphic)item).color = color;
			}
		}

		private void SetActiveStyle(int row, bool active)
		{
			//IL_0072: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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)
			((Component)_names[row]).gameObject.SetActive(true);
			((Component)_times[row]).gameObject.SetActive(true);
			Color color = (active ? new Color(1f, 1f, 1f, _config.Opacity) : new Color(1f, 1f, 1f, 0.82f * _config.Opacity));
			((Graphic)_names[row]).color = color;
			((Graphic)_times[row]).color = color;
			((TMP_Text)_names[row]).fontSize = (active ? 23f : 22f);
			((TMP_Text)_times[row]).fontSize = (active ? 23f : 22f);
		}

		private void ApplyNativeStyleWhenAvailable()
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = FindVersionText();
			if ((Object)(object)val != (Object)null)
			{
				_font = ((TMP_Text)val).font;
				_sharedMaterial = ((TMP_Text)val).fontSharedMaterial;
			}
			LocalizationManager val2 = Object.FindObjectOfType<LocalizationManager>(true);
			if ((Object)(object)val2 != (Object)null)
			{
				FieldInfo field = typeof(LocalizationManager).GetField("_defaultFontAsset", BindingFlags.Instance | BindingFlags.NonPublic);
				FieldInfo field2 = typeof(LocalizationManager).GetField("_backdropFontAsset", BindingFlags.Instance | BindingFlags.NonPublic);
				if ((Object)(object)_font == (Object)null && field != null)
				{
					ref TMP_FontAsset font = ref _font;
					object? value = field.GetValue(val2);
					font = (TMP_FontAsset)((value is TMP_FontAsset) ? value : null);
				}
				if (field2 != null)
				{
					ref TMP_FontAsset backdropFont = ref _backdropFont;
					object? value2 = field2.GetValue(val2);
					backdropFont = (TMP_FontAsset)((value2 is TMP_FontAsset) ? value2 : null);
				}
			}
			if ((Object)(object)_font == (Object)null)
			{
				return;
			}
			foreach (TextMeshProUGUI item in AllTexts())
			{
				((TMP_Text)item).font = _font;
				if ((Object)(object)_sharedMaterial != (Object)null)
				{
					((TMP_Text)item).fontSharedMaterial = _sharedMaterial;
				}
				((Graphic)item).color = Color.white;
				((TMP_Text)item).outlineColor = new Color32((byte)20, (byte)18, (byte)18, byte.MaxValue);
				((TMP_Text)item).outlineWidth = 0.18f;
				((TMP_Text)item).characterSpacing = 0.5f;
			}
		}

		private TextMeshProUGUI FindVersionText()
		{
			TextMeshProUGUI[] array = Resources.FindObjectsOfTypeAll<TextMeshProUGUI>();
			TextMeshProUGUI[] array2 = array;
			foreach (TextMeshProUGUI val in array2)
			{
				if ((Object)(object)val != (Object)null && ((TMP_Text)val).text != null && ((TMP_Text)val).text.IndexOf("Version", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return val;
				}
			}
			return null;
		}

		private IEnumerable<TextMeshProUGUI> AllTexts()
		{
			yield return _category;
			yield return _timer;
			foreach (TextMeshProUGUI name in _names)
			{
				yield return name;
			}
			foreach (TextMeshProUGUI time in _times)
			{
				yield return time;
			}
		}

		private static RectTransform CreateRect(string name, Transform parent)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = new Vector2(1f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(1f, 1f);
			return component;
		}

		private static TextMeshProUGUI CreateText(string name, Transform parent, float size, FontStyles style, TextAlignmentOptions alignment)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0052: 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)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(parent, false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).fontSize = size;
			((TMP_Text)component).fontStyle = style;
			((TMP_Text)component).alignment = alignment;
			((TMP_Text)component).enableWordWrapping = false;
			((Graphic)component).raycastTarget = false;
			((TMP_Text)component).overflowMode = (TextOverflowModes)0;
			return component;
		}

		private static void SetRect(RectTransform rect, float x, float y, float width, float height)
		{
			//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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(1f, 1f);
			rect.anchorMax = new Vector2(1f, 1f);
			rect.pivot = new Vector2(1f, 1f);
			rect.anchoredPosition = new Vector2(x, y);
			rect.sizeDelta = new Vector2(width, height);
		}
	}
}