Decompiled source of AllSleepNightSkip v0.1.6

BepInEx/plugins/Exothermic.AllSleepNightSkip/Exothermic.AllSleepNightSkip.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Exothermic.AllSleepNightSkip")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.6.0")]
[assembly: AssemblyInformationalVersion("0.1.6+d7c1a503fe21d48de2ab96880f13536f394ff5ff")]
[assembly: AssemblyProduct("Exothermic.AllSleepNightSkip")]
[assembly: AssemblyTitle("Exothermic.AllSleepNightSkip")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.5.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Exothermic.AllSleepNightSkip
{
	[BepInPlugin("com.exothermic.aska.allsleepnightskip", "Exothermic All-Sleep Night Skip", "0.1.6")]
	public sealed class Plugin : BasePlugin
	{
		public const string PluginGuid = "com.exothermic.aska.allsleepnightskip";

		public const string PluginName = "Exothermic All-Sleep Night Skip";

		public const string PluginVersion = "0.1.5";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> RequiredSleepFraction;

		internal static ConfigEntry<int> MinimumPlayers;

		internal static ConfigEntry<float> StartDelaySeconds;

		internal static ConfigEntry<float> FastForwardScale;

		internal static ConfigEntry<float> MaximumFastForwardRealSeconds;

		internal static ConfigEntry<bool> OnlyAtNight;

		internal static ConfigEntry<bool> AllowUnknownNightState;

		internal static ConfigEntry<float> MorningHour;

		internal static ConfigEntry<float> PlayerScanInterval;

		internal static ConfigEntry<bool> AuthorityOnly;

		internal static ConfigEntry<bool> DiagnosticLogging;

		internal static ConfigEntry<bool> DumpDiscoveryOnWorldLoad;

		public override void Load()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Expected O, but got Unknown
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Expected O, but got Unknown
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable automatic night fast-forwarding when the required players are asleep.");
			RequiredSleepFraction = ((BasePlugin)this).Config.Bind<float>("Sleep", "RequiredSleepFraction", 1f, new ConfigDescription("Fraction of active players that must be asleep. 1.0 means everyone.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 1f), Array.Empty<object>()));
			MinimumPlayers = ((BasePlugin)this).Config.Bind<int>("Sleep", "MinimumPlayers", 1, new ConfigDescription("Minimum number of active players required.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 64), Array.Empty<object>()));
			StartDelaySeconds = ((BasePlugin)this).Config.Bind<float>("Sleep", "StartDelaySeconds", 3f, new ConfigDescription("All players must remain asleep for this many real seconds before fast-forward starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>()));
			FastForwardScale = ((BasePlugin)this).Config.Bind<float>("FastForward", "TimeScale", 20f, new ConfigDescription("Unity simulation speed while skipping. Lower this if the server stutters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 100f), Array.Empty<object>()));
			MaximumFastForwardRealSeconds = ((BasePlugin)this).Config.Bind<float>("FastForward", "MaximumRealSeconds", 120f, new ConfigDescription("Safety timeout measured in real seconds. The normal time scale is always restored afterward.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 600f), Array.Empty<object>()));
			OnlyAtNight = ((BasePlugin)this).Config.Bind<bool>("FastForward", "OnlyAtNight", true, "Do not begin fast-forwarding when the discovered world clock says it is daytime.");
			AllowUnknownNightState = ((BasePlugin)this).Config.Bind<bool>("FastForward", "AllowUnknownNightState", true, "Allow the skip when the mod cannot identify ASKA's clock. Disable this to prevent daytime naps from triggering it.");
			MorningHour = ((BasePlugin)this).Config.Bind<float>("FastForward", "MorningHour", 6f, new ConfigDescription("Hour at which the skip should stop when a 0-24 world clock is discovered.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(4f, 10f), Array.Empty<object>()));
			PlayerScanInterval = ((BasePlugin)this).Config.Bind<float>("Advanced", "PlayerScanIntervalSeconds", 1f, new ConfigDescription("Real-time interval between player and sleep-state checks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f), Array.Empty<object>()));
			AuthorityOnly = ((BasePlugin)this).Config.Bind<bool>("Advanced", "AuthorityOnly", true, "Only alter time on a dedicated server, single-player host, Fusion server, or shared-mode master client.");
			DiagnosticLogging = ((BasePlugin)this).Config.Bind<bool>("Diagnostics", "VerboseLogging", false, "Write player, sleep-state, clock, and authority details to BepInEx/LogOutput.log.");
			DumpDiscoveryOnWorldLoad = ((BasePlugin)this).Config.Bind<bool>("Diagnostics", "DumpDiscoveryOnWorldLoad", false, "Dump sleep- and clock-related components/members once after entering the world.");
			CharacterSpawnTracker.Install();
			((BasePlugin)this).AddComponent<NightSkipBehaviour>();
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(96, 7, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Exothermic All-Sleep Night Skip");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.1.5");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded. Enabled=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Enabled.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", AuthorityOnly=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(AuthorityOnly.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", VerboseLogging=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(DiagnosticLogging.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", DumpDiscoveryOnWorldLoad=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(DumpDiscoveryOnWorldLoad.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ScanInterval=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(PlayerScanInterval.Value, "0.##");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s.");
			}
			log.LogInfo(val);
		}
	}
	internal static class CharacterSpawnTracker
	{
		private static readonly object Sync = new object();

		private static readonly List<WeakReference> SpawnedCharacters = new List<WeakReference>();

		private static bool _installAttempted;

		public static void Install()
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Expected O, but got Unknown
			//IL_0085: 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_009a: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			if (_installAttempted)
			{
				return;
			}
			_installAttempted = true;
			bool flag = default(bool);
			try
			{
				Type resolvedCharacterType = PlayerProbe.GetResolvedCharacterType();
				if (resolvedCharacterType == null)
				{
					Plugin.Log.LogWarning((object)"Character.Spawned tracker not installed: SSSGame.Character wrapper was not found. Exact-type scanning will still be used.");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(resolvedCharacterType, "Spawned", Type.EmptyTypes, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(CharacterSpawnTracker), "AfterCharacterSpawned", (Type[])null, (Type[])null);
				if (methodInfo == null || methodInfo2 == null)
				{
					Plugin.Log.LogWarning((object)"Character.Spawned tracker not installed: Spawned method or postfix was not found.");
					return;
				}
				new Harmony("com.exothermic.aska.allsleepnightskip.character-tracker").Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(41, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Character.Spawned tracker installed on ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(resolvedCharacterType.FullName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(methodInfo.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
			}
			catch (Exception ex)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(49, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Character.Spawned tracker installation failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.GetType().Name);
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log2.LogWarning(val2);
			}
		}

		private static void AfterCharacterSpawned(object __instance)
		{
			Component val = (Component)((__instance is Component) ? __instance : null);
			if (val == null || (Object)(object)val == (Object)null)
			{
				return;
			}
			lock (Sync)
			{
				for (int num = SpawnedCharacters.Count - 1; num >= 0; num--)
				{
					object? target = SpawnedCharacters[num].Target;
					Component val2 = (Component)((target is Component) ? target : null);
					if (val2 == null || (Object)(object)val2 == (Object)null)
					{
						SpawnedCharacters.RemoveAt(num);
					}
					else if (((Object)val2).GetInstanceID() == ((Object)val).GetInstanceID())
					{
						return;
					}
				}
				SpawnedCharacters.Add(new WeakReference(val));
			}
		}

		public static List<Component> Snapshot()
		{
			List<Component> list = new List<Component>();
			lock (Sync)
			{
				for (int num = SpawnedCharacters.Count - 1; num >= 0; num--)
				{
					object? target = SpawnedCharacters[num].Target;
					Component val = (Component)((target is Component) ? target : null);
					if (val == null || (Object)(object)val == (Object)null)
					{
						SpawnedCharacters.RemoveAt(num);
					}
					else
					{
						list.Add(val);
					}
				}
				return list;
			}
		}
	}
	public sealed class NightSkipBehaviour : MonoBehaviour
	{
		private readonly ReflectionCache _reflection = new ReflectionCache();

		private readonly WorldClockProbe _clock = new WorldClockProbe();

		private float _nextScanRealtime;

		private float _allSleepingSince = -1f;

		private float _fastForwardStartedRealtime;

		private float _previousTimeScale = 1f;

		private float _previousFixedDeltaTime = 0.02f;

		private bool _fastForwarding;

		private bool _sleepCycleLatched;

		private int _discoveryDumpsForScene;

		private float _nextDiscoveryDumpRealtime;

		private string _lastSceneName = string.Empty;

		private bool _sawNightDuringFastForward;

		private void Awake()
		{
			Plugin.Log.LogInfo((object)"NightSkipBehaviour is active; Update loop started.");
		}

		private void Update()
		{
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Expected O, but got Unknown
			//IL_0590: Unknown result type (might be due to invalid IL or missing references)
			//IL_0597: Expected O, but got Unknown
			if (!Plugin.Enabled.Value)
			{
				StopFastForward("mod disabled");
				ResetSleepReadiness();
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < _nextScanRealtime)
			{
				return;
			}
			_nextScanRealtime = realtimeSinceStartup + Plugin.PlayerScanInterval.Value;
			string text = SafeActiveSceneName();
			if (!string.Equals(text, _lastSceneName, StringComparison.Ordinal))
			{
				StopFastForward("scene changed");
				ResetSleepReadiness();
				_clock.Reset();
				_reflection.ResetSceneCaches();
				_discoveryDumpsForScene = 0;
				_nextDiscoveryDumpRealtime = 0f;
				_lastSceneName = text;
			}
			bool flag = LooksLikeGameplayScene(text);
			AuthorityState authorityState = AuthorityProbe.GetAuthorityState(_reflection);
			List<PlayerRecord> list = PlayerProbe.FindActivePlayers(_reflection);
			int num = 0;
			foreach (PlayerRecord item in list)
			{
				if ((item.SleepState = SleepProbe.GetSleepState(item, _reflection)).IsSleeping)
				{
					num++;
				}
			}
			int num2 = ((list.Count > 0) ? Mathf.CeilToInt((float)list.Count * Plugin.RequiredSleepFraction.Value) : Plugin.MinimumPlayers.Value);
			bool flag2 = list.Count >= Plugin.MinimumPlayers.Value && num >= num2;
			ClockState clockState = _clock.Sample(_reflection, Plugin.MorningHour.Value);
			bool flag3 = list.Count > 0 && list.All((PlayerRecord p) => p.SleepState.Confidence <= 0f);
			bool flag4 = _discoveryDumpsForScene == 0 || (flag3 && _discoveryDumpsForScene < 3 && realtimeSinceStartup >= _nextDiscoveryDumpRealtime);
			if (Plugin.DumpDiscoveryOnWorldLoad.Value && list.Count > 0 && flag4)
			{
				_discoveryDumpsForScene++;
				_nextDiscoveryDumpRealtime = realtimeSinceStartup + 15f;
				DiscoveryDump.Write(list, authorityState, clockState, _reflection);
			}
			bool flag5 = default(bool);
			if (Plugin.DiagnosticLogging.Value)
			{
				string text2 = string.Join(", ", list.Select((PlayerRecord p) => $"{p.Name}:{p.SleepState}"));
				string text3 = ((Plugin.AuthorityOnly.Value && authorityState == AuthorityState.NotAuthority) ? "blocked:not-authority" : ((list.Count < Plugin.MinimumPlayers.Value) ? $"waiting:players<{Plugin.MinimumPlayers.Value}" : (flag2 ? "ready:all-sleeping" : "waiting:sleep")));
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(112, 12, ref flag5);
				if (flag5)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("scan gate=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text3);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" playerProbe=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(PlayerProbe.LastProbeSummary);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" activeScene='");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' sceneHint=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(flag);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loadedScenes=[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(SafeLoadedSceneNames());
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] authority=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<AuthorityState>(authorityState);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" players=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" sleeping=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clock=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ClockState>(clockState);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" fast=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(_fastForwarding);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" [");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]");
				}
				log.LogInfo(val);
			}
			if (Plugin.AuthorityOnly.Value && authorityState == AuthorityState.NotAuthority)
			{
				StopFastForward("this peer is not the world authority");
				ResetSleepReadiness();
			}
			else if (list.Count < Plugin.MinimumPlayers.Value)
			{
				StopFastForward("not enough active players");
				ResetSleepReadiness();
			}
			else if (_fastForwarding)
			{
				if (clockState.IsNight == true)
				{
					_sawNightDuringFastForward = true;
				}
				if (!flag2)
				{
					StopFastForward("a required player woke up or disconnected");
					_sleepCycleLatched = true;
				}
				else if (clockState.IsMorning == true || (_sawNightDuringFastForward && clockState.IsNight == false))
				{
					StopFastForward("morning reached");
					_sleepCycleLatched = true;
				}
				else if (realtimeSinceStartup - _fastForwardStartedRealtime >= Plugin.MaximumFastForwardRealSeconds.Value)
				{
					StopFastForward("safety timeout reached");
					_sleepCycleLatched = true;
				}
				else
				{
					EnsureFastForwardScale();
				}
			}
			else if (!flag2)
			{
				ResetSleepReadiness();
				_sleepCycleLatched = false;
			}
			else
			{
				if (_sleepCycleLatched)
				{
					return;
				}
				if (Plugin.OnlyAtNight.Value)
				{
					bool? isNight = clockState.IsNight;
					flag5 = false;
					if (isNight == flag5)
					{
						ResetSleepReadiness();
						return;
					}
					if (!clockState.IsNight.HasValue && !Plugin.AllowUnknownNightState.Value)
					{
						ResetSleepReadiness();
						return;
					}
				}
				if (_allSleepingSince < 0f)
				{
					_allSleepingSince = realtimeSinceStartup;
					ManualLogSource log2 = Plugin.Log;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(59, 3, ref flag5);
					if (flag5)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Sleep threshold reached (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); starting ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Plugin.StartDelaySeconds.Value, "0.0");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s confirmation delay.");
					}
					log2.LogInfo(val);
				}
				else if (realtimeSinceStartup - _allSleepingSince >= Plugin.StartDelaySeconds.Value)
				{
					StartFastForward(list.Count, num, clockState, authorityState);
				}
			}
		}

		private void StartFastForward(int playerCount, int sleepingCount, ClockState clockState, AuthorityState authority)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			if (!_fastForwarding)
			{
				_previousTimeScale = Time.timeScale;
				_previousFixedDeltaTime = Time.fixedDeltaTime;
				_fastForwardStartedRealtime = Time.realtimeSinceStartup;
				_sawNightDuringFastForward = clockState.IsNight == true;
				_fastForwarding = true;
				EnsureFastForwardScale();
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(68, 5, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Night fast-forward started: sleeping=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(sleepingCount);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(playerCount);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", scale=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Plugin.FastForwardScale.Value, "0.##");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("x, authority=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<AuthorityState>(authority);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", clock=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ClockState>(clockState);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogWarning(val);
			}
		}

		private void EnsureFastForwardScale()
		{
			float value = Plugin.FastForwardScale.Value;
			if (!Mathf.Approximately(Time.timeScale, value))
			{
				Time.timeScale = value;
			}
			if (!Mathf.Approximately(Time.fixedDeltaTime, _previousFixedDeltaTime))
			{
				Time.fixedDeltaTime = _previousFixedDeltaTime;
			}
		}

		private void StopFastForward(string reason)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			if (_fastForwarding)
			{
				Time.timeScale = Mathf.Max(0.01f, _previousTimeScale);
				Time.fixedDeltaTime = Mathf.Max(0.0001f, _previousFixedDeltaTime);
				_fastForwarding = false;
				_allSleepingSince = -1f;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(50, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Night fast-forward stopped: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(". Restored timeScale=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(Time.timeScale, "0.###");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogWarning(val);
			}
		}

		private void ResetSleepReadiness()
		{
			_allSleepingSince = -1f;
		}

		private void OnDestroy()
		{
			StopFastForward("plugin behaviour destroyed");
		}

		private void OnApplicationQuit()
		{
			StopFastForward("application quitting");
		}

		private static bool LooksLikeGameplayScene(string sceneName)
		{
			if (string.IsNullOrWhiteSpace(sceneName))
			{
				return false;
			}
			string text = sceneName.ToLowerInvariant();
			if (!text.Contains("streamingworld") && !text.Contains("world"))
			{
				return text.Contains("game");
			}
			return true;
		}

		private static string SafeActiveSceneName()
		{
			//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)
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene)).name ?? string.Empty;
			}
			catch
			{
				return string.Empty;
			}
		}

		private static string SafeLoadedSceneNames()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<string> list = new List<string>();
				for (int i = 0; i < SceneManager.sceneCount; i++)
				{
					Scene sceneAt = SceneManager.GetSceneAt(i);
					if (((Scene)(ref sceneAt)).IsValid())
					{
						list.Add(((Scene)(ref sceneAt)).name ?? string.Empty);
					}
				}
				return string.Join(",", list);
			}
			catch (Exception ex)
			{
				return "<scene-list-failed:" + ex.GetType().Name + ">";
			}
		}
	}
	internal enum AuthorityState
	{
		Unknown,
		Authority,
		NotAuthority
	}
	internal sealed class PlayerRecord
	{
		public GameObject Root { get; set; }

		public Component CharacterComponent { get; set; }

		public string Name { get; set; } = string.Empty;

		public SleepState SleepState { get; set; } = SleepState.Unknown("not sampled");
	}
	internal readonly struct SleepState
	{
		public bool IsSleeping { get; }

		public float Confidence { get; }

		public string Reason { get; }

		public SleepState(bool isSleeping, float confidence, string reason)
		{
			IsSleeping = isSleeping;
			Confidence = confidence;
			Reason = reason;
		}

		public static SleepState Sleeping(float confidence, string reason)
		{
			return new SleepState(isSleeping: true, confidence, reason);
		}

		public static SleepState Awake(float confidence, string reason)
		{
			return new SleepState(isSleeping: false, confidence, reason);
		}

		public static SleepState Unknown(string reason)
		{
			return new SleepState(isSleeping: false, 0f, reason);
		}

		public override string ToString()
		{
			return $"{(IsSleeping ? "sleep" : ((Confidence > 0f) ? "awake" : "unknown"))}({Confidence:0.00}:{Reason})";
		}
	}
	internal readonly struct ClockState
	{
		public bool? IsNight { get; }

		public bool? IsMorning { get; }

		public double? Hour { get; }

		public string Source { get; }

		public ClockState(bool? isNight, bool? isMorning, double? hour, string source)
		{
			IsNight = isNight;
			IsMorning = isMorning;
			Hour = hour;
			Source = source;
		}

		public static ClockState Unknown(string source)
		{
			return new ClockState(null, null, null, source);
		}

		public override string ToString()
		{
			string value = (Hour.HasValue ? Hour.Value.ToString("0.00") : "?");
			return $"night={IsNight?.ToString() ?? "?"},morning={IsMorning?.ToString() ?? "?"},hour={value},source={Source}";
		}
	}
	internal static class PlayerProbe
	{
		private static readonly string[] CharacterTypeHints = new string[4] { "SSSGame.Character", ".PlayerCharacter", ".NetworkPlayer", ".PlayerController" };

		private static Type _characterType;

		private static MethodInfo _resourcesFindAllGeneric;

		private static MethodInfo _objectFindAllGeneric;

		public static string LastProbeSummary { get; private set; } = "not-run";

		public static List<PlayerRecord> FindActivePlayers(ReflectionCache cache)
		{
			List<PlayerRecord> list = new List<PlayerRecord>();
			HashSet<int> hashSet = new HashSet<int>();
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			string text = string.Empty;
			foreach (Component item in CharacterSpawnTracker.Snapshot())
			{
				num++;
				TryAddCharacter(item, cache, list, hashSet);
			}
			Type type = ResolveCharacterType();
			if (type != null)
			{
				try
				{
					foreach (Component item2 in FindAllComponentsOfExactType(type))
					{
						num2++;
						TryAddCharacter(item2, cache, list, hashSet);
					}
				}
				catch (Exception ex)
				{
					text = ex.GetType().Name;
				}
			}
			IEnumerable<MonoBehaviour> enumerable;
			try
			{
				enumerable = (IEnumerable<MonoBehaviour>)Object.FindObjectsOfType<MonoBehaviour>();
			}
			catch
			{
				enumerable = Array.Empty<MonoBehaviour>();
			}
			foreach (MonoBehaviour item3 in enumerable)
			{
				if (!((Object)(object)item3 == (Object)null) && !((Object)(object)((Component)item3).gameObject == (Object)null))
				{
					Type type2 = ((object)item3).GetType();
					string fullName = type2.FullName ?? type2.Name;
					if (CharacterTypeHints.Any((string h) => fullName.Contains(h, StringComparison.OrdinalIgnoreCase)))
					{
						num3++;
						TryAddCharacter((Component)(object)item3, cache, list, hashSet);
					}
				}
			}
			try
			{
				foreach (GameObject item4 in (Il2CppArrayBase<GameObject>)(object)GameObject.FindGameObjectsWithTag("Player"))
				{
					num4++;
					if (!((Object)(object)item4 == (Object)null) && hashSet.Add(((Object)item4).GetInstanceID()))
					{
						Component val = ((IEnumerable<Component>)item4.GetComponentsInChildren<Component>(true)).FirstOrDefault((Func<Component, bool>)((Component c) => (Object)(object)c != (Object)null && (((object)c).GetType().FullName ?? ((object)c).GetType().Name).Contains("Character", StringComparison.OrdinalIgnoreCase)));
						if (!((Object)(object)val == (Object)null))
						{
							list.Add(new PlayerRecord
							{
								Root = item4,
								CharacterComponent = val,
								Name = BuildPlayerName(item4, list.Count + 1)
							});
						}
					}
				}
			}
			catch
			{
			}
			string value = type?.FullName ?? "missing";
			LastProbeSummary = $"type={value},tracked={num},exact={num2},broad={num3},tagged={num4},accepted={list.Count}" + (string.IsNullOrEmpty(text) ? string.Empty : (",exactError=" + text));
			return list;
		}

		private static void TryAddCharacter(Component character, ReflectionCache cache, List<PlayerRecord> result, HashSet<int> seen)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)character == (Object)null || (Object)(object)character.gameObject == (Object)null)
			{
				return;
			}
			try
			{
				Scene scene = character.gameObject.scene;
				if (!((Scene)(ref scene)).IsValid() || !((Scene)(ref scene)).isLoaded)
				{
					return;
				}
			}
			catch
			{
				return;
			}
			Type type = ((object)character).GetType();
			string? obj2 = type.FullName ?? type.Name;
			string text = ((Object)character.gameObject).name ?? string.Empty;
			bool flag = text.Contains("CharacterAska", StringComparison.OrdinalIgnoreCase) || text.Contains("PlayerCharacter", StringComparison.OrdinalIgnoreCase);
			bool flag2 = obj2.Contains("Player", StringComparison.OrdinalIgnoreCase) || flag;
			MethodInfo method = cache.GetMethod(type, "IsPlayer", Type.EmptyTypes);
			if (method != null)
			{
				try
				{
					if (method.Invoke(character, null) is bool flag3)
					{
						flag2 = flag3 || flag;
					}
				}
				catch
				{
				}
			}
			if (!flag2 && _characterType != null && _characterType.IsInstanceOfType(character))
			{
				_ = method == null;
			}
			else if (flag2)
			{
				GameObject val = FindLikelyPlayerRoot(character.gameObject);
				int instanceID = ((Object)val).GetInstanceID();
				if (seen.Add(instanceID))
				{
					result.Add(new PlayerRecord
					{
						Root = val,
						CharacterComponent = character,
						Name = BuildPlayerName(val, result.Count + 1)
					});
				}
			}
		}

		internal static Type GetResolvedCharacterType()
		{
			return ResolveCharacterType();
		}

		private static Type ResolveCharacterType()
		{
			if (_characterType != null)
			{
				return _characterType;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType("SSSGame.Character", throwOnError: false, ignoreCase: false);
					if (type != null && typeof(Component).IsAssignableFrom(type))
					{
						_characterType = type;
						return _characterType;
					}
				}
				catch
				{
				}
			}
			assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly2 in assemblies)
			{
				try
				{
					Type type2 = assembly2.GetTypes().FirstOrDefault((Type t) => typeof(Component).IsAssignableFrom(t) && string.Equals(t.Name, "Character", StringComparison.OrdinalIgnoreCase) && cacheHasIsPlayer(t));
					if (type2 != null)
					{
						_characterType = type2;
						return _characterType;
					}
				}
				catch
				{
				}
			}
			return null;
			static bool cacheHasIsPlayer(Type type3)
			{
				try
				{
					return type3.GetMethod("IsPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) != null;
				}
				catch
				{
					return false;
				}
			}
		}

		private static IEnumerable<Component> FindAllComponentsOfExactType(Type targetType)
		{
			List<Component> list = new List<Component>();
			try
			{
				if ((object)_resourcesFindAllGeneric == null)
				{
					_resourcesFindAllGeneric = typeof(Resources).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "FindObjectsOfTypeAll" && m.IsGenericMethodDefinition && m.GetParameters().Length == 0);
				}
				if (_resourcesFindAllGeneric != null)
				{
					foreach (object item in Enumerate(_resourcesFindAllGeneric.MakeGenericMethod(targetType).Invoke(null, null)))
					{
						Component val = (Component)((item is Component) ? item : null);
						if (val != null)
						{
							list.Add(val);
						}
					}
				}
			}
			catch
			{
			}
			if (list.Count > 0)
			{
				return list;
			}
			try
			{
				if ((object)_objectFindAllGeneric == null)
				{
					_objectFindAllGeneric = typeof(Object).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "FindObjectsOfType" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(bool));
				}
				if (_objectFindAllGeneric != null)
				{
					foreach (object item2 in Enumerate(_objectFindAllGeneric.MakeGenericMethod(targetType).Invoke(null, new object[1] { true })))
					{
						Component val2 = (Component)((item2 is Component) ? item2 : null);
						if (val2 != null)
						{
							list.Add(val2);
						}
					}
				}
			}
			catch
			{
			}
			return list;
		}

		private static IEnumerable<object> Enumerate(object raw)
		{
			if (!(raw is IEnumerable enumerable))
			{
				yield break;
			}
			foreach (object item in enumerable)
			{
				yield return item;
			}
		}

		private static GameObject FindLikelyPlayerRoot(GameObject origin)
		{
			Transform val = origin.transform;
			GameObject result = origin;
			for (int i = 0; i < 6; i++)
			{
				if (!((Object)(object)val != (Object)null))
				{
					break;
				}
				string text = ((Object)val).name.ToLowerInvariant();
				if (text.Contains("player") || text.Contains("character"))
				{
					result = ((Component)val).gameObject;
				}
				val = val.parent;
			}
			return result;
		}

		private static string BuildPlayerName(GameObject root, int fallbackIndex)
		{
			string text = ((Object)root).name;
			if (string.IsNullOrWhiteSpace(text))
			{
				text = $"Player{fallbackIndex}";
			}
			return text;
		}
	}
	internal static class SleepProbe
	{
		private sealed class GraphNode
		{
			public object Value { get; }

			public string Path { get; }

			public int Depth { get; }

			public GraphNode(object value, string path, int depth)
			{
				Value = value;
				Path = path;
				Depth = depth;
			}
		}

		private static readonly string[] ExactSleepNames = new string[14]
		{
			"IsSleeping", "Sleeping", "IsAsleep", "Asleep", "InBed", "IsInBed", "_isSleeping", "_sleeping", "_isAsleep", "_asleep",
			"_inBed", "_isInBed", "m_IsSleeping", "m_Sleeping"
		};

		private static readonly string[] SleepTokens = new string[7] { "sleep", "asleep", "inbed", "bedinteraction", "resting", "lying", "laying" };

		private static readonly string[] StrongSleepTokens = new string[12]
		{
			"issleeping", "sleeping", "asleep", "inbed", "sleepinteraction", "bedinteraction", "restinteraction", "resting", "lyingdown", "layingdown",
			"wakeupinteraction", "wakeup"
		};

		private static readonly string[] StateMemberTokens = new string[8] { "state", "status", "action", "activity", "interaction", "pose", "mode", "moveset" };

		private static readonly string[] GraphContextTokens = new string[20]
		{
			"current", "active", "selected", "running", "interaction", "action", "activity", "state", "status", "pose",
			"mode", "moveset", "target", "task", "agent", "controller", "station", "occup", "animation", "anim"
		};

		private static readonly string[] GraphSkipMemberTokens = new string[16]
		{
			"gameobject", "transform", "parent", "root", "children", "material", "renderer", "mesh", "texture", "shader",
			"sprite", "audio", "camera", "light", "collider", "rigidbody"
		};

		private const int MaxGraphDepth = 4;

		private const int MaxGraphNodes = 128;

		public static SleepState GetSleepState(PlayerRecord player, ReflectionCache cache)
		{
			SleepState result = SleepState.Unknown("no sleep signal");
			IEnumerable<Component> componentsInChildren;
			try
			{
				componentsInChildren = (IEnumerable<Component>)player.Root.GetComponentsInChildren<Component>(true);
			}
			catch
			{
				return result;
			}
			Component[] array = componentsInChildren.Where((Component c) => (Object)(object)c != (Object)null).ToArray();
			Component[] array2 = array;
			foreach (Component val in array2)
			{
				Type type = ((object)val).GetType();
				string text = type.FullName ?? type.Name;
				MemberAccessor[] readableMembers = cache.GetReadableMembers(type);
				foreach (MemberAccessor memberAccessor in readableMembers)
				{
					string memberName = memberAccessor.Name;
					int num3 = Array.FindIndex(ExactSleepNames, (string n) => string.Equals(n, memberName, StringComparison.OrdinalIgnoreCase));
					if (memberAccessor.ValueType == typeof(bool) && num3 >= 0)
					{
						if (memberAccessor.TryGet(val, out var value) && value is bool flag)
						{
							float num4 = 1f - (float)num3 * 0.01f;
							if (flag)
							{
								return SleepState.Sleeping(num4, type.Name + "." + memberName + "=true");
							}
							if (num4 > result.Confidence)
							{
								result = SleepState.Awake(num4, type.Name + "." + memberName + "=false");
							}
						}
						continue;
					}
					bool flag2 = ContainsAny(memberName, SleepTokens);
					object value3;
					if (memberAccessor.ValueType == typeof(bool) && flag2)
					{
						if (memberAccessor.TryGet(val, out var value2) && value2 is bool flag3)
						{
							float num5 = 0.92f;
							if (flag3)
							{
								return SleepState.Sleeping(num5, type.Name + "." + memberName + "=true");
							}
							if (num5 > result.Confidence)
							{
								result = SleepState.Awake(num5, type.Name + "." + memberName + "=false");
							}
						}
					}
					else if ((ContainsAny(memberName, StateMemberTokens) || flag2) && memberAccessor.TryGet(val, out value3) && value3 != null)
					{
						string value4 = SafeDescribe(value3);
						if (ContainsStrongSleepSignal(value4))
						{
							return SleepState.Sleeping(0.9f, $"{type.Name}.{memberName}={Shorten(value4, 80)}");
						}
					}
				}
				if (ContainsStrongSleepSignal(text))
				{
					bool activeInHierarchy = val.gameObject.activeInHierarchy;
					Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
					if (activeInHierarchy && ((Object)(object)val2 == (Object)null || val2.enabled))
					{
						return SleepState.Sleeping(0.72f, "active component " + text);
					}
				}
				Animator val3 = (Animator)(object)((val is Animator) ? val : null);
				if (val3 != null)
				{
					SleepState sleepState = ReadAnimator(val3);
					if (sleepState.IsSleeping)
					{
						return sleepState;
					}
					if (sleepState.Confidence > result.Confidence)
					{
						result = sleepState;
					}
				}
			}
			string summary;
			SleepState sleepState2 = ReadInteractionGraph(player, array, cache, out summary);
			if (sleepState2.IsSleeping)
			{
				return sleepState2;
			}
			if (sleepState2.Confidence > result.Confidence)
			{
				result = sleepState2;
			}
			string text2 = BuildHierarchySignal(player.Root.transform);
			if (ContainsAny(text2, new string[4] { "sleeping", "inbed", "bedinteraction", "sleepinteraction" }))
			{
				return SleepState.Sleeping(0.6f, "hierarchy=" + text2);
			}
			if (result.Confidence > 0f)
			{
				return result;
			}
			return SleepState.Unknown(string.IsNullOrEmpty(summary) ? "no sleep signal" : ("no sleep signal; graph=" + summary));
		}

		private static SleepState ReadInteractionGraph(PlayerRecord player, Component[] components, ReflectionCache cache, out string summary)
		{
			Queue<GraphNode> queue = new Queue<GraphNode>();
			HashSet<int> hashSet = new HashSet<int>();
			List<string> list = new List<string>();
			EnqueueGraphRoot(queue, player.CharacterComponent, "Character", 0);
			foreach (Component val in components)
			{
				string value = ((object)val).GetType().FullName ?? ((object)val).GetType().Name;
				if (ContainsAny(value, GraphContextTokens) || ContainsAny(value, SleepTokens))
				{
					EnqueueGraphRoot(queue, val, ((object)val).GetType().Name, 0);
				}
			}
			int num = 0;
			SleepState result = SleepState.Unknown("no interaction sleep signal");
			while (queue.Count > 0 && num++ < 128)
			{
				GraphNode graphNode = queue.Dequeue();
				object value2 = graphNode.Value;
				if (value2 == null)
				{
					continue;
				}
				int hashCode;
				try
				{
					hashCode = value2.GetHashCode();
				}
				catch
				{
					hashCode = graphNode.Path.GetHashCode();
				}
				if (!hashSet.Add(hashCode))
				{
					continue;
				}
				Type type;
				try
				{
					type = value2.GetType();
				}
				catch
				{
					continue;
				}
				string text = type.FullName ?? type.Name;
				bool flag = ContainsAny(graphNode.Path, GraphContextTokens);
				string text2 = SafeDescribe(value2);
				if (flag && (ContainsStrongSleepSignal(text) || ContainsStrongSleepSignal(text2)))
				{
					summary = JoinNotes(list);
					return SleepState.Sleeping(0.91f, "graph:" + graphNode.Path + "=" + Shorten(text + ":" + text2, 100));
				}
				MemberAccessor[] readableMembers;
				try
				{
					readableMembers = cache.GetReadableMembers(type);
				}
				catch
				{
					continue;
				}
				MemberAccessor[] array = readableMembers;
				foreach (MemberAccessor memberAccessor in array)
				{
					string memberName = memberAccessor.Name;
					if (ContainsAny(memberName, GraphSkipMemberTokens) || !memberAccessor.TryGet(value2, out var value3) || value3 == null)
					{
						continue;
					}
					string text3 = graphNode.Path + "." + memberName;
					bool flag2 = flag || ContainsAny(memberName, GraphContextTokens);
					int num2 = Array.FindIndex(ExactSleepNames, (string n) => string.Equals(n, memberName, StringComparison.OrdinalIgnoreCase));
					if (value3 is bool flag3)
					{
						if (num2 >= 0 || ContainsAny(memberName, SleepTokens))
						{
							float num3 = ((num2 >= 0) ? 0.98f : 0.9f);
							if (flag3)
							{
								summary = JoinNotes(list);
								return SleepState.Sleeping(num3, "graph:" + text3 + "=true");
							}
							if (num3 > result.Confidence)
							{
								result = SleepState.Awake(num3, "graph:" + text3 + "=false");
							}
						}
						continue;
					}
					string text4;
					try
					{
						text4 = value3.GetType().FullName ?? value3.GetType().Name;
					}
					catch
					{
						text4 = string.Empty;
					}
					string text5 = SafeDescribe(value3);
					string value4 = memberName + " " + text4 + " " + text5;
					if (flag2 && ContainsStrongSleepSignal(value4))
					{
						summary = JoinNotes(list);
						return SleepState.Sleeping(0.93f, "graph:" + text3 + "=" + Shorten(text4 + ":" + text5, 100));
					}
					if (flag2 && list.Count < 6)
					{
						list.Add(Shorten(text3 + "=" + text4 + ":" + text5, 90));
					}
					if (graphNode.Depth < 4 && ShouldTraverse(value3, memberName, flag2))
					{
						queue.Enqueue(new GraphNode(value3, text3, graphNode.Depth + 1));
					}
				}
			}
			summary = JoinNotes(list);
			return result;
		}

		internal static List<string> DescribeInteractionGraph(PlayerRecord player, ReflectionCache cache, int maxLines)
		{
			List<string> list = new List<string>();
			Queue<GraphNode> queue = new Queue<GraphNode>();
			HashSet<int> hashSet = new HashSet<int>();
			EnqueueGraphRoot(queue, player.CharacterComponent, "Character", 0);
			Component[] array;
			try
			{
				array = ((IEnumerable<Component>)player.Root.GetComponentsInChildren<Component>(true)).Where((Component c) => (Object)(object)c != (Object)null).ToArray();
			}
			catch
			{
				array = Array.Empty<Component>();
			}
			Component[] array2 = array;
			foreach (Component val in array2)
			{
				string value = ((object)val).GetType().FullName ?? ((object)val).GetType().Name;
				if (ContainsAny(value, GraphContextTokens) || ContainsAny(value, SleepTokens))
				{
					EnqueueGraphRoot(queue, val, ((object)val).GetType().Name, 0);
				}
			}
			int num2 = 0;
			while (queue.Count > 0 && num2++ < 128 && list.Count < maxLines)
			{
				GraphNode graphNode = queue.Dequeue();
				object value2 = graphNode.Value;
				if (value2 == null)
				{
					continue;
				}
				int hashCode;
				try
				{
					hashCode = value2.GetHashCode();
				}
				catch
				{
					hashCode = graphNode.Path.GetHashCode();
				}
				if (!hashSet.Add(hashCode))
				{
					continue;
				}
				Type type;
				try
				{
					type = value2.GetType();
				}
				catch
				{
					continue;
				}
				string value3 = type.FullName ?? type.Name;
				list.Add($"GRAPH depth={graphNode.Depth} path={graphNode.Path} type={value3} text={Shorten(SafeDescribe(value2), 120)}");
				MemberAccessor[] readableMembers;
				try
				{
					readableMembers = cache.GetReadableMembers(type);
				}
				catch
				{
					continue;
				}
				MemberAccessor[] array3 = readableMembers;
				foreach (MemberAccessor memberAccessor in array3)
				{
					if (list.Count >= maxLines)
					{
						break;
					}
					string name = memberAccessor.Name;
					if (!ContainsAny(name, GraphSkipMemberTokens) && memberAccessor.TryGet(value2, out var value4) && value4 != null)
					{
						string text = graphNode.Path + "." + name;
						bool flag = ContainsAny(graphNode.Path, GraphContextTokens) || ContainsAny(name, GraphContextTokens) || ContainsAny(name, SleepTokens);
						string value5;
						try
						{
							value5 = value4.GetType().FullName ?? value4.GetType().Name;
						}
						catch
						{
							value5 = string.Empty;
						}
						string value6 = SafeDescribe(value4);
						if (flag || ContainsStrongSleepSignal(value5) || ContainsStrongSleepSignal(value6))
						{
							list.Add($"  {text} [{value5}] = {Shorten(value6, 140)}");
						}
						if (graphNode.Depth < 4 && ShouldTraverse(value4, name, flag))
						{
							queue.Enqueue(new GraphNode(value4, text, graphNode.Depth + 1));
						}
					}
				}
			}
			if (list.Count == 0)
			{
				list.Add("GRAPH no traversable interaction/state objects were found");
			}
			return list;
		}

		private static void EnqueueGraphRoot(Queue<GraphNode> queue, object value, string path, int depth)
		{
			if (value != null)
			{
				queue.Enqueue(new GraphNode(value, path, depth));
			}
		}

		private static bool ShouldTraverse(object raw, string memberName, bool memberContext)
		{
			if (raw == null)
			{
				return false;
			}
			Type type;
			try
			{
				type = raw.GetType();
			}
			catch
			{
				return false;
			}
			if (type.IsPrimitive || type.IsEnum || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(TimeSpan) || type == typeof(Type))
			{
				return false;
			}
			if (raw is IEnumerable)
			{
				return false;
			}
			if (raw is GameObject || raw is Transform)
			{
				return false;
			}
			if (raw is Object && !(raw is Component))
			{
				return false;
			}
			string value = type.FullName ?? type.Name;
			if (memberContext)
			{
				return true;
			}
			if (ContainsAny(memberName, GraphContextTokens) || ContainsAny(value, GraphContextTokens))
			{
				return true;
			}
			if (ContainsAny(memberName, SleepTokens) || ContainsStrongSleepSignal(value))
			{
				return true;
			}
			string text = type.Namespace ?? string.Empty;
			if (text.StartsWith("SSSGame", StringComparison.Ordinal) || text.StartsWith("SandSailorStudio", StringComparison.Ordinal))
			{
				return ContainsAny(memberName, new string[5] { "agent", "controller", "state", "interaction", "action" });
			}
			return false;
		}

		private static SleepState ReadAnimator(Animator animator)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Invalid comparison between Unknown and I4
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)animator == (Object)null || (Object)(object)animator.runtimeAnimatorController == (Object)null || animator.layerCount <= 0)
				{
					return SleepState.Unknown("animator has no controller/layers");
				}
				foreach (AnimatorControllerParameter item in (Il2CppArrayBase<AnimatorControllerParameter>)(object)animator.parameters)
				{
					if ((int)item.type == 4 && ContainsAny(item.name, SleepTokens))
					{
						return animator.GetBool(item.nameHash) ? SleepState.Sleeping(0.88f, "Animator." + item.name + "=true") : SleepState.Awake(0.7f, "Animator." + item.name + "=false");
					}
				}
				for (int i = 0; i < animator.layerCount; i++)
				{
					foreach (AnimatorClipInfo item2 in (Il2CppArrayBase<AnimatorClipInfo>)(object)animator.GetCurrentAnimatorClipInfo(i))
					{
						AnimatorClipInfo current2 = item2;
						if (!((Object)(object)((AnimatorClipInfo)(ref current2)).clip == (Object)null))
						{
							string text = ((Object)((AnimatorClipInfo)(ref current2)).clip).name ?? string.Empty;
							if (ContainsStrongSleepSignal(text))
							{
								return SleepState.Sleeping(0.86f, "AnimatorClip=" + text);
							}
						}
					}
				}
			}
			catch
			{
			}
			return SleepState.Unknown("no animator sleep parameter/clip");
		}

		private static string BuildHierarchySignal(Transform root)
		{
			List<string> list = new List<string>();
			Transform val = root;
			for (int i = 0; i < 6; i++)
			{
				if (!((Object)(object)val != (Object)null))
				{
					break;
				}
				list.Add(((Object)val).name.Replace(" ", string.Empty).ToLowerInvariant());
				val = val.parent;
			}
			return string.Join("/", list);
		}

		private static bool ContainsStrongSleepSignal(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			string normalized = value.Replace(" ", string.Empty).Replace("_", string.Empty).Replace("-", string.Empty)
				.ToLowerInvariant();
			return StrongSleepTokens.Any((string token) => normalized.Contains(token.Replace(" ", string.Empty).Replace("_", string.Empty).Replace("-", string.Empty), StringComparison.OrdinalIgnoreCase));
		}

		private static string SafeDescribe(object value)
		{
			if (value == null)
			{
				return "null";
			}
			try
			{
				return value.ToString() ?? value.GetType().Name;
			}
			catch
			{
				return value.GetType().Name;
			}
		}

		private static string Shorten(string value, int maxLength)
		{
			if (string.IsNullOrEmpty(value) || value.Length <= maxLength)
			{
				return value ?? string.Empty;
			}
			return value.Substring(0, maxLength - 3) + "...";
		}

		private static string JoinNotes(List<string> notes)
		{
			if (notes == null || notes.Count == 0)
			{
				return string.Empty;
			}
			return string.Join(" | ", notes.Take(4));
		}

		internal static bool ContainsAny(string value, IEnumerable<string> tokens)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			return tokens.Any((string token) => value.Contains(token, StringComparison.OrdinalIgnoreCase));
		}
	}
	internal static class AuthorityProbe
	{
		private static readonly string[] PositiveMembers = new string[3] { "IsServer", "IsSharedModeMasterClient", "IsSinglePlayer" };

		private static readonly string[] NegativeMembers = new string[1] { "IsClient" };

		public static AuthorityState GetAuthorityState(ReflectionCache cache)
		{
			if (Application.isBatchMode)
			{
				return AuthorityState.Authority;
			}
			IEnumerable<MonoBehaviour> enumerable;
			try
			{
				enumerable = (IEnumerable<MonoBehaviour>)Object.FindObjectsOfType<MonoBehaviour>();
			}
			catch
			{
				return AuthorityState.Unknown;
			}
			foreach (MonoBehaviour item in enumerable)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				Type type = ((object)item).GetType();
				if (!(type.FullName ?? type.Name).Contains("NetworkRunner", StringComparison.OrdinalIgnoreCase))
				{
					continue;
				}
				bool flag = false;
				string[] positiveMembers = PositiveMembers;
				foreach (string name in positiveMembers)
				{
					if (cache.TryReadNamedBoolean(item, name, out var value))
					{
						flag = true;
						if (value)
						{
							return AuthorityState.Authority;
						}
					}
				}
				if (flag)
				{
					return AuthorityState.NotAuthority;
				}
				positiveMembers = NegativeMembers;
				foreach (string name2 in positiveMembers)
				{
					if (cache.TryReadNamedBoolean(item, name2, out var value2) && !value2)
					{
						return AuthorityState.Authority;
					}
				}
			}
			return AuthorityState.Unknown;
		}
	}
	internal sealed class WorldClockProbe
	{
		private readonly Dictionary<string, double> _lastNumericValues = new Dictionary<string, double>();

		private ClockCandidate _cached;

		private float _nextDiscoveryRealtime;

		private bool _observedNight;

		private static readonly string[] TypeTokens = new string[12]
		{
			"daynight", "daycycle", "timeofday", "worldtime", "gametime", "timecontroller", "timemanager", "calendar", "worldclock", "skycontroller",
			"suncontroller", "seasonmanager"
		};

		private static readonly string[] ExcludedMemberTokens = new string[15]
		{
			"delta", "duration", "timer", "cooldown", "elapsed", "speed", "scale", "tick", "update", "interval",
			"network", "last", "start", "end", "timeout"
		};

		public void Reset()
		{
			_cached = null;
			_nextDiscoveryRealtime = 0f;
			_lastNumericValues.Clear();
			_observedNight = false;
		}

		public ClockState Sample(ReflectionCache cache, float morningHour)
		{
			if (_cached != null && _cached.TryRead(out var state, morningHour))
			{
				if (state.IsNight == true)
				{
					_observedNight = true;
				}
				if (_observedNight && state.IsNight == false)
				{
					state = new ClockState(state.IsNight, true, state.Hour, state.Source);
				}
				return state;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= _nextDiscoveryRealtime)
			{
				_nextDiscoveryRealtime = realtimeSinceStartup + 5f;
				_cached = Discover(cache);
				if (_cached != null && _cached.TryRead(out var state2, morningHour))
				{
					if (state2.IsNight == true)
					{
						_observedNight = true;
					}
					if (_observedNight && state2.IsNight == false)
					{
						state2 = new ClockState(state2.IsNight, true, state2.Hour, state2.Source);
					}
					return state2;
				}
			}
			ClockState result = ReadSunFallback();
			if (result.IsNight == true)
			{
				_observedNight = true;
			}
			if (_observedNight && result.IsNight == false)
			{
				result = new ClockState(result.IsNight, true, result.Hour, result.Source);
			}
			return result;
		}

		private ClockCandidate Discover(ReflectionCache cache)
		{
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Expected O, but got Unknown
			IEnumerable<MonoBehaviour> enumerable;
			try
			{
				enumerable = (IEnumerable<MonoBehaviour>)Object.FindObjectsOfType<MonoBehaviour>();
			}
			catch
			{
				return null;
			}
			List<ClockCandidate> list = new List<ClockCandidate>();
			foreach (MonoBehaviour item in enumerable)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				Type type = ((object)item).GetType();
				string typeName = type.FullName ?? type.Name;
				int num = TypeTokens.Sum((string token) => typeName.Contains(token, StringComparison.OrdinalIgnoreCase) ? 20 : 0);
				if (num == 0)
				{
					continue;
				}
				MemberAccessor[] readableMembers = cache.GetReadableMembers(type);
				foreach (MemberAccessor memberAccessor in readableMembers)
				{
					string name = memberAccessor.Name;
					if (ExcludedMemberTokens.Any((string t) => name.Contains(t, StringComparison.OrdinalIgnoreCase)))
					{
						continue;
					}
					if (memberAccessor.ValueType == typeof(bool))
					{
						int num3 = num + ScoreBooleanMember(name);
						if (num3 > num)
						{
							list.Add(new ClockCandidate((Component)(object)item, memberAccessor, ClockValueKind.Boolean, num3));
						}
					}
					else
					{
						if (!ReflectionCache.IsNumericType(memberAccessor.ValueType))
						{
							continue;
						}
						int num4 = num + ScoreNumericMember(name);
						if (num4 <= num || !memberAccessor.TryGet(item, out var value) || !ReflectionCache.TryConvertDouble(value, out var number))
						{
							continue;
						}
						ClockValueKind clockValueKind = InferNumericKind(name, number);
						if (clockValueKind != ClockValueKind.Unknown)
						{
							string key = $"{typeName}.{name}:{((Object)item).GetInstanceID()}";
							if (_lastNumericValues.TryGetValue(key, out var value2) && Math.Abs(number - value2) > 1E-06)
							{
								num4 += 25;
							}
							_lastNumericValues[key] = number;
							list.Add(new ClockCandidate((Component)(object)item, memberAccessor, clockValueKind, num4));
						}
					}
				}
			}
			ClockCandidate clockCandidate = list.OrderByDescending((ClockCandidate c) => c.Score).FirstOrDefault();
			if (Plugin.DiagnosticLogging.Value && clockCandidate != null)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(23, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("World clock candidate: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ClockCandidate>(clockCandidate);
				}
				log.LogInfo(val);
			}
			return clockCandidate;
		}

		private static int ScoreBooleanMember(string name)
		{
			if (name.Equals("IsNight", StringComparison.OrdinalIgnoreCase))
			{
				return 100;
			}
			if (name.Equals("IsDay", StringComparison.OrdinalIgnoreCase))
			{
				return 95;
			}
			if (name.Equals("IsDaytime", StringComparison.OrdinalIgnoreCase))
			{
				return 95;
			}
			if (name.Equals("IsMorning", StringComparison.OrdinalIgnoreCase))
			{
				return 90;
			}
			if (name.Contains("night", StringComparison.OrdinalIgnoreCase))
			{
				return 70;
			}
			if (name.Contains("day", StringComparison.OrdinalIgnoreCase))
			{
				return 50;
			}
			if (name.Contains("morning", StringComparison.OrdinalIgnoreCase))
			{
				return 60;
			}
			return 0;
		}

		private static int ScoreNumericMember(string name)
		{
			if (name.Equals("Hour", StringComparison.OrdinalIgnoreCase))
			{
				return 100;
			}
			if (name.Equals("CurrentHour", StringComparison.OrdinalIgnoreCase))
			{
				return 100;
			}
			if (name.Contains("timeofday", StringComparison.OrdinalIgnoreCase))
			{
				return 90;
			}
			if (name.Contains("daytime", StringComparison.OrdinalIgnoreCase))
			{
				return 80;
			}
			if (name.Contains("normalized", StringComparison.OrdinalIgnoreCase) && name.Contains("time", StringComparison.OrdinalIgnoreCase))
			{
				return 85;
			}
			if (name.Contains("dayprogress", StringComparison.OrdinalIgnoreCase))
			{
				return 80;
			}
			if (name.Contains("clock", StringComparison.OrdinalIgnoreCase))
			{
				return 70;
			}
			if (name.Contains("hour", StringComparison.OrdinalIgnoreCase))
			{
				return 65;
			}
			if (name.Equals("Time", StringComparison.OrdinalIgnoreCase))
			{
				return 30;
			}
			return 0;
		}

		private static ClockValueKind InferNumericKind(string name, double value)
		{
			if (name.Contains("hour", StringComparison.OrdinalIgnoreCase) && value >= 0.0 && value <= 24.1)
			{
				return ClockValueKind.Hour24;
			}
			if (value >= 0.0 && value <= 1.01 && (name.Contains("normalized", StringComparison.OrdinalIgnoreCase) || name.Contains("progress", StringComparison.OrdinalIgnoreCase)))
			{
				return ClockValueKind.NormalizedDay;
			}
			if (value >= 0.0 && value <= 24.1 && (name.Contains("time", StringComparison.OrdinalIgnoreCase) || name.Contains("clock", StringComparison.OrdinalIgnoreCase)))
			{
				return ClockValueKind.Hour24;
			}
			if (value >= 0.0 && value <= 1440.1 && name.Contains("minute", StringComparison.OrdinalIgnoreCase))
			{
				return ClockValueKind.Minutes1440;
			}
			return ClockValueKind.Unknown;
		}

		private static ClockState ReadSunFallback()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<Light> list = new List<Light>();
				try
				{
					foreach (Light item in Resources.FindObjectsOfTypeAll<Light>())
					{
						if (!((Object)(object)item == (Object)null) && (int)item.type == 1 && !((Object)(object)((Component)item).gameObject == (Object)null))
						{
							Scene scene = ((Component)item).gameObject.scene;
							if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded)
							{
								list.Add(item);
							}
						}
					}
				}
				catch
				{
					list.AddRange(((IEnumerable<Light>)Object.FindObjectsOfType<Light>()).Where((Light l) => (Object)(object)l != (Object)null && (int)l.type == 1));
				}
				Light val = ((IEnumerable<Light>)list).FirstOrDefault((Func<Light, bool>)((Light l) => ((Object)l).name.Contains("sun", StringComparison.OrdinalIgnoreCase) && !((Object)l).name.Contains("moon", StringComparison.OrdinalIgnoreCase)));
				Light val2 = ((IEnumerable<Light>)list).FirstOrDefault((Func<Light, bool>)((Light l) => ((Object)l).name.Contains("moon", StringComparison.OrdinalIgnoreCase)));
				Light val3 = val ?? RenderSettings.sun ?? val2 ?? list.OrderByDescending((Light l) => l.intensity).FirstOrDefault();
				if ((Object)(object)val3 == (Object)null)
				{
					return ClockState.Unknown("no clock or directional light found");
				}
				float num = 0f - ((Component)val3).transform.forward.y;
				if (((Object)val3).name.Contains("moon", StringComparison.OrdinalIgnoreCase))
				{
					bool flag = num > 0.02f;
					return new ClockState(flag, !flag, null, $"moon:{((Object)val3).name}:{num:0.000}");
				}
				bool value = num < -0.02f;
				bool value2 = num >= 0.03f;
				return new ClockState(value, value2, null, $"sun:{((Object)val3).name}:{num:0.000}");
			}
			catch (Exception ex)
			{
				return ClockState.Unknown("sun/moon probe failed:" + ex.GetType().Name);
			}
		}
	}
	internal enum ClockValueKind
	{
		Unknown,
		Boolean,
		Hour24,
		NormalizedDay,
		Minutes1440
	}
	internal sealed class ClockCandidate
	{
		private readonly Component _component;

		private readonly MemberAccessor _member;

		private readonly ClockValueKind _kind;

		public int Score { get; }

		public ClockCandidate(Component component, MemberAccessor member, ClockValueKind kind, int score)
		{
			_component = component;
			_member = member;
			_kind = kind;
			Score = score;
		}

		public bool TryRead(out ClockState state, float morningHour)
		{
			state = ClockState.Unknown(ToString());
			if ((Object)(object)_component == (Object)null || !_member.TryGet(_component, out var value) || value == null)
			{
				return false;
			}
			string name = _member.Name;
			if (_kind == ClockValueKind.Boolean && value is bool flag)
			{
				bool? isNight = null;
				bool? isMorning = null;
				if (name.Contains("night", StringComparison.OrdinalIgnoreCase))
				{
					isNight = flag;
				}
				else if (name.Contains("morning", StringComparison.OrdinalIgnoreCase))
				{
					isMorning = flag;
				}
				else if (name.Contains("day", StringComparison.OrdinalIgnoreCase))
				{
					isNight = !flag;
				}
				state = new ClockState(isNight, isMorning, null, ToString());
				return true;
			}
			if (!ReflectionCache.TryConvertDouble(value, out var number))
			{
				return false;
			}
			double num = _kind switch
			{
				ClockValueKind.Hour24 => Normalize24(number), 
				ClockValueKind.NormalizedDay => Normalize24(number * 24.0), 
				ClockValueKind.Minutes1440 => Normalize24(number / 60.0), 
				_ => double.NaN, 
			};
			if (double.IsNaN(num))
			{
				return false;
			}
			bool value2 = num >= 18.0 || num < (double)morningHour - 0.25;
			bool value3 = num >= (double)morningHour && num < (double)morningHour + 3.0;
			state = new ClockState(value2, value3, num, ToString());
			return true;
		}

		private static double Normalize24(double value)
		{
			value %= 24.0;
			if (value < 0.0)
			{
				value += 24.0;
			}
			return value;
		}

		public override string ToString()
		{
			return $"{((object)_component).GetType().Name}.{_member.Name}/{_kind}/score={Score}";
		}
	}
	internal static class DiscoveryDump
	{
		private static readonly string[] InterestingTokens = new string[17]
		{
			"sleep", "asleep", "bed", "rest", "state", "action", "activity", "interaction", "pose", "night",
			"day", "morning", "hour", "time", "clock", "calendar", "season"
		};

		public static void Write(List<PlayerRecord> players, AuthorityState authority, ClockState clock, ReflectionCache cache)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Expected O, but got Unknown
			Plugin.Log.LogWarning((object)"=== ALL-SLEEP NIGHT SKIP DISCOVERY START ===");
			ManualLogSource log = Plugin.Log;
			bool flag = default(bool);
			BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(28, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Authority=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<AuthorityState>(authority);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; clock=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ClockState>(clock);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("; players=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(players.Count);
			}
			log.LogWarning(val);
			foreach (PlayerRecord player in players)
			{
				ManualLogSource log2 = Plugin.Log;
				val = new BepInExWarningLogInterpolatedStringHandler(28, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("--- Player ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(player.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" root=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(GetPath(player.Root.transform));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" state=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<SleepState>(player.SleepState);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ---");
				}
				log2.LogWarning(val);
				IEnumerable<Component> componentsInChildren;
				try
				{
					componentsInChildren = (IEnumerable<Component>)player.Root.GetComponentsInChildren<Component>(true);
				}
				catch
				{
					continue;
				}
				foreach (Component item in componentsInChildren)
				{
					if ((Object)(object)item == (Object)null)
					{
						continue;
					}
					Type type = ((object)item).GetType();
					string text = type.FullName ?? type.Name;
					bool num = SleepProbe.ContainsAny(text, InterestingTokens);
					MemberAccessor[] array = (from m in cache.GetReadableMembers(type)
						where SleepProbe.ContainsAny(m.Name, InterestingTokens)
						select m).ToArray();
					if (!num && array.Length == 0)
					{
						continue;
					}
					ManualLogSource log3 = Plugin.Log;
					val = new BepInExWarningLogInterpolatedStringHandler(27, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("COMPONENT ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" object=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(GetPath(item.transform));
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" enabled=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ReadEnabled(item));
					}
					log3.LogWarning(val);
					MemberAccessor[] array2 = array;
					foreach (MemberAccessor memberAccessor in array2)
					{
						object value;
						string text2 = ((!memberAccessor.TryGet(item, out value)) ? "<unreadable>" : (value?.ToString() ?? "null"));
						ManualLogSource log4 = Plugin.Log;
						val = new BepInExWarningLogInterpolatedStringHandler(6, 3, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("  ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(memberAccessor.ValueType.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(memberAccessor.Name);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" = ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
						}
						log4.LogWarning(val);
					}
				}
				Plugin.Log.LogWarning((object)"--- Recursive interaction/state graph ---");
				foreach (string item2 in SleepProbe.DescribeInteractionGraph(player, cache, 100))
				{
					Plugin.Log.LogWarning((object)item2);
				}
			}
			Plugin.Log.LogWarning((object)"=== ALL-SLEEP NIGHT SKIP DISCOVERY END ===");
		}

		private static string ReadEnabled(Component component)
		{
			Behaviour val = (Behaviour)(object)((component is Behaviour) ? component : null);
			if (val == null)
			{
				return "n/a";
			}
			return val.enabled.ToString();
		}

		private static string GetPath(Transform transform)
		{
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			int num = 0;
			while ((Object)(object)parent != (Object)null && num++ < 12)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}
	}
	internal sealed class ReflectionCache
	{
		private readonly Dictionary<Type, MemberAccessor[]> _readableMembers = new Dictionary<Type, MemberAccessor[]>();

		private readonly Dictionary<(Type Type, string Name), MemberAccessor> _namedMembers = new Dictionary<(Type, string), MemberAccessor>();

		private readonly Dictionary<(Type Type, string Name, string Signature), MethodInfo> _methods = new Dictionary<(Type, string, string), MethodInfo>();

		public MemberAccessor[] GetReadableMembers(Type type)
		{
			if (_readableMembers.TryGetValue(type, out var value))
			{
				return value;
			}
			List<MemberAccessor> list = new List<MemberAccessor>();
			try
			{
				PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo propertyInfo in properties)
				{
					MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true);
					if (!(getMethod == null) && !getMethod.IsStatic && propertyInfo.GetIndexParameters().Length == 0)
					{
						list.Add(new MemberAccessor(propertyInfo));
					}
				}
			}
			catch
			{
			}
			try
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsStatic)
					{
						list.Add(new MemberAccessor(fieldInfo));
					}
				}
			}
			catch
			{
			}
			value = (from g in list.GroupBy<MemberAccessor, string>((MemberAccessor v) => v.Name, StringComparer.OrdinalIgnoreCase)
				select g.First()).ToArray();
			_readableMembers[type] = value;
			return value;
		}

		public bool TryReadNamedBoolean(object instance, string name, out bool value)
		{
			value = false;
			Type type = instance.GetType();
			(Type, string) key = (type, name);
			if (!_namedMembers.TryGetValue(key, out var value2))
			{
				value2 = GetReadableMembers(type).FirstOrDefault((MemberAccessor m) => m.ValueType == typeof(bool) && string.Equals(m.Name, name, StringComparison.OrdinalIgnoreCase));
				_namedMembers[key] = value2;
			}
			if (value2 == null || !value2.TryGet(instance, out var value3) || !(value3 is bool flag))
			{
				return false;
			}
			value = flag;
			return true;
		}

		public MethodInfo GetMethod(Type type, string name, Type[] parameters)
		{
			string item = string.Join(",", parameters.Select((Type t) => t.FullName));
			(Type, string, string) key = (type, name, item);
			if (_methods.TryGetValue(key, out var value))
			{
				return value;
			}
			try
			{
				value = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null);
			}
			catch
			{
				value = null;
			}
			_methods[key] = value;
			return value;
		}

		public void ResetSceneCaches()
		{
		}

		public static bool IsNumericType(Type type)
		{
			Type type2 = Nullable.GetUnderlyingType(type) ?? type;
			if (!(type2 == typeof(byte)) && !(type2 == typeof(sbyte)) && !(type2 == typeof(short)) && !(type2 == typeof(ushort)) && !(type2 == typeof(int)) && !(type2 == typeof(uint)) && !(type2 == typeof(long)) && !(type2 == typeof(ulong)) && !(type2 == typeof(float)) && !(type2 == typeof(double)))
			{
				return type2 == typeof(decimal);
			}
			return true;
		}

		public static bool TryConvertDouble(object value, out double number)
		{
			number = 0.0;
			if (value == null)
			{
				return false;
			}
			try
			{
				number = Convert.ToDouble(value, CultureInfo.InvariantCulture);
				return !double.IsNaN(number) && !double.IsInfinity(number);
			}
			catch
			{
				return false;
			}
		}
	}
	internal sealed class MemberAccessor
	{
		private readonly PropertyInfo _property;

		private readonly FieldInfo _field;

		public string Name { get; }

		public Type ValueType { get; }

		public MemberAccessor(PropertyInfo property)
		{
			_property = property;
			Name = property.Name;
			ValueType = property.PropertyType;
		}

		public MemberAccessor(FieldInfo field)
		{
			_field = field;
			Name = field.Name;
			ValueType = field.FieldType;
		}

		public bool TryGet(object instance, out object value)
		{
			value = null;
			try
			{
				value = ((_property != null) ? _property.GetValue(instance) : _field?.GetValue(instance));
				return true;
			}
			catch
			{
				return false;
			}
		}
	}
}