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;
}
}
}
}