Decompiled source of DynamicLongerDays v1.1.0

DynamicLongerDays.dll

Decompiled 9 hours ago
using System;
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 BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("slivkonsin")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("DynamicLongerDays")]
[assembly: AssemblyTitle("DynamicLongerDays")]
[assembly: AssemblyVersion("1.1.0.0")]
[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 DynamicLongerDays
{
	internal sealed class Config
	{
		private const int CurrentConfigVersion = 5;

		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<float> MorningSpeedE;

		public readonly ConfigEntry<float> EveningSpeedE;

		public readonly ConfigEntry<float> TransitionStartHourE;

		public readonly ConfigEntry<float> TransitionEndHourE;

		public readonly ConfigEntry<bool> MoonDifficultyEnabled;

		public readonly ConfigEntry<float> MorningSpeedNormalE;

		public readonly ConfigEntry<float> MorningSpeedEasyE;

		public readonly ConfigEntry<string> MorningSpeedOverrides;

		public readonly ConfigEntry<float> MinSpeedE;

		public readonly ConfigEntry<float> MaxSpeedE;

		public readonly ConfigEntry<bool> EnemyEffectEnabled;

		public readonly ConfigEntry<float> MaxSpeedUpE;

		public readonly ConfigEntry<float> MaxSlowDownE;

		public readonly ConfigEntry<float> NeutralDangerE;

		public readonly ConfigEntry<float> OutsideShareE;

		public readonly ConfigEntry<bool> DeadPlayerEffectEnabled;

		public readonly ConfigEntry<float> DeadPlayersMaxSlowDownE;

		public readonly ConfigEntry<bool> RevivesRemovePenalty;

		public readonly ConfigEntry<bool> LeaveEarlyBoostEnabled;

		public readonly ConfigEntry<float> LeaveEarlySpeedE;

		public readonly ConfigEntry<bool> ApparatusEffectEnabled;

		public readonly ConfigEntry<float> ApparatusSlowDownE;

		public readonly ConfigEntry<bool> EclipsedOverride;

		public readonly ConfigEntry<float> EclipsedSpeedE;

		public readonly ConfigEntry<bool> DebugLog;

		public readonly ConfigEntry<bool> Clock24h;

		private readonly ConfigEntry<int> _version;

		public float MorningSpeed => Num(MorningSpeedE, 0.1f, 5f);

		public float MorningSpeedNormal => Num(MorningSpeedNormalE, 0.1f, 5f);

		public float MorningSpeedEasy => Num(MorningSpeedEasyE, 0.1f, 5f);

		public float EveningSpeed => Num(EveningSpeedE, 0.1f, 5f);

		public float TransitionStartHour => Num(TransitionStartHourE, 6f, 24f);

		public float TransitionEndHour => Num(TransitionEndHourE, 6f, 24f);

		public float MinSpeed => Math.Min(Num(MinSpeedE, 0.1f, 5f), Num(MaxSpeedE, 0.1f, 5f));

		public float MaxSpeed => Math.Max(Num(MinSpeedE, 0.1f, 5f), Num(MaxSpeedE, 0.1f, 5f));

		public float MaxSpeedUp => Num(MaxSpeedUpE, 0f, 2f);

		public float MaxSlowDown => Num(MaxSlowDownE, 0f, 2f);

		public float NeutralDanger => Num(NeutralDangerE, 0.01f, 0.99f);

		public float OutsideWeight => Num(OutsideShareE, 0f, 1f);

		public float InsideWeight => 1f - OutsideWeight;

		public float DeadPlayersMaxSlowDown => Num(DeadPlayersMaxSlowDownE, 0f, 2f);

		public float ApparatusSlowDown => Num(ApparatusSlowDownE, 0f, 2f);

		public float LeaveEarlySpeed => Num(LeaveEarlySpeedE, 1f, 5f);

		public float ShipAreaMargin => 2.5f;

		public float EclipsedSpeed => Num(EclipsedSpeedE, 0.1f, 5f);

		public float SmoothingSeconds => 6f;

		private static AcceptableValueRange<float> R(float a, float b)
		{
			return new AcceptableValueRange<float>(a, b);
		}

		public Config(ConfigFile c)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Expected O, but got Unknown
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Expected O, but got Unknown
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Expected O, but got Unknown
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Expected O, but got Unknown
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Expected O, but got Unknown
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Expected O, but got Unknown
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Expected O, but got Unknown
			//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Expected O, but got Unknown
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_043c: Expected O, but got Unknown
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Expected O, but got Unknown
			Enabled = c.Bind<bool>("1. General", "Enabled", true, "Turns the whole mod on or off. When off, days run at their normal speed.\n1.0 is normal speed, 2.0 is twice as fast, 0.5 is half as fast. Applied on top of the moon's own day speed. In multiplayer, the host's settings are used for everyone.");
			MorningSpeedE = c.Bind<float>("2. Day rhythm", "MorningSpeed", 1.6f, new ConfigDescription("How fast time runs from landing until the slow-down begins, on the hardest moons.\nIf MoonDifficulty is turned off, this is used on every moon.", (AcceptableValueBase)(object)R(0.1f, 5f), Array.Empty<object>()));
			MoonDifficultyEnabled = c.Bind<bool>("2. Day rhythm", "MoonDifficulty", true, "Mornings go by slower on easier moons, since fewer and weaker enemies spawn there. Works with modded moons too.\nThe log shows how every installed moon is rated when the game loads.");
			MorningSpeedNormalE = c.Bind<float>("2. Day rhythm", "MorningSpeedNormal", 1.4f, new ConfigDescription("Morning speed on an average moon. Moons in between easy, average and hard get a speed in between.", (AcceptableValueBase)(object)R(0.1f, 5f), Array.Empty<object>()));
			MorningSpeedEasyE = c.Bind<float>("2. Day rhythm", "MorningSpeedEasy", 1f, new ConfigDescription("Morning speed on the easiest moons.", (AcceptableValueBase)(object)R(0.1f, 5f), Array.Empty<object>()));
			MorningSpeedOverrides = c.Bind<string>("2. Day rhythm", "MorningSpeedOverrides", "", "Set the morning speed of specific moons yourself, instead of using their rating. Separate moons with commas.\nExample: Synthesis=1.3, Experimentation=1\nMoons that can't be rated (some modded moons) count as an average moon unless they're listed here.");
			TransitionStartHourE = c.Bind<float>("2. Day rhythm", "SlowDownStartHour", 8.5f, new ConfigDescription("In-game time at which the day starts to slow down, on a 24-hour clock. Use decimals for minutes: 8.5 = 8:30.", (AcceptableValueBase)(object)R(6f, 24f), Array.Empty<object>()));
			TransitionEndHourE = c.Bind<float>("2. Day rhythm", "SlowDownEndHour", 13f, new ConfigDescription("In-game time at which the slow-down is complete (13 = 13:00, 13.5 = 13:30). Between the start and end time the speed changes gradually.\nIf this is not later than the start time, the speed changes in one step at the start time.", (AcceptableValueBase)(object)R(6f, 24f), Array.Empty<object>()));
			EveningSpeedE = c.Bind<float>("2. Day rhythm", "EveningSpeed", 0.7f, new ConfigDescription("How fast time runs after the slow-down, until midnight.", (AcceptableValueBase)(object)R(0.1f, 5f), Array.Empty<object>()));
			MinSpeedE = c.Bind<float>("3. Speed limits", "MinSpeed", 0.5f, new ConfigDescription("The slowest time can ever run, no matter how the effects below add up.", (AcceptableValueBase)(object)R(0.1f, 5f), Array.Empty<object>()));
			MaxSpeedE = c.Bind<float>("3. Speed limits", "MaxSpeed", 1.7f, new ConfigDescription("The fastest time can normally run, outside of the leave-early boost. If MaxSpeed is set lower than MinSpeed, the two values are swapped.", (AcceptableValueBase)(object)R(0.1f, 5f), Array.Empty<object>()));
			EnemyEffectEnabled = c.Bind<bool>("4. Enemies", "Enabled", true, "Makes time run faster while the moon is quiet and slower whilst dangerous.\nThe measurement of danger is as follows: every moon has a limit on how many enemies it can hold, weighted by how dangerous each enemy is. Danger is the share of that limit currently alive (0 = no enemies, 1 = the moon is full). Killed enemies stop counting straight away. Harmless daytime creatures such as Manticoils and bees are completely ignored.");
			NeutralDangerE = c.Bind<float>("4. Enemies", "NeutralDanger", 0.3f, new ConfigDescription("The danger level at which enemies have no effect on time. Below it, time speeds up, and above it, it slows down.\nExample: At 0.3, a small amount of minor enemies would yield no change, whereas a Bracken with a Forest Giant would clearly slow it down.", (AcceptableValueBase)(object)R(0.01f, 0.99f), Array.Empty<object>()));
			MaxSpeedUpE = c.Bind<float>("4. Enemies", "MaxSpeedUp", 0.2f, new ConfigDescription("How much faster time runs when no enemies are alive at all.", (AcceptableValueBase)(object)R(0f, 2f), Array.Empty<object>()));
			MaxSlowDownE = c.Bind<float>("4. Enemies", "MaxSlowDown", 0.35f, new ConfigDescription("How much slower time runs when the moon is completely full of enemies.", (AcceptableValueBase)(object)R(0f, 2f), Array.Empty<object>()));
			OutsideShareE = c.Bind<float>("4. Enemies", "OutsideShare", 0.65f, new ConfigDescription("How much of the danger comes from enemies outside; the rest comes from enemies inside the facility. 0.65 means outside enemies count for 65% and inside enemies for 35%. Outside enemies count more by default because they cut off the way back to the ship.", (AcceptableValueBase)(object)R(0f, 1f), Array.Empty<object>()));
			DeadPlayerEffectEnabled = c.Bind<bool>("5. Dead players", "Enabled", true, "Every player death slows time down for the rest of the day. Works with any lobby size, including MoreCompany lobbies.");
			DeadPlayersMaxSlowDownE = c.Bind<float>("5. Dead players", "MaxSlowDown", 0.12f, new ConfigDescription("The total slow-down if the whole lobby had died. Each death adds an equal share: with 4 players, every death slows time by 0.03.", (AcceptableValueBase)(object)R(0f, 2f), Array.Empty<object>()));
			RevivesRemovePenalty = c.Bind<bool>("5. Dead players", "RevivesRemovePenalty", true, "If a dead player is revived (by a revive mod), their share of the slow-down is removed again. If you want to make every death count nonetheless, turn this off.");
			ApparatusEffectEnabled = c.Bind<bool>("6. Apparatus", "Enabled", true, "Slows time down for the rest of the day once someone pulls the apparatus.");
			ApparatusSlowDownE = c.Bind<float>("6. Apparatus", "SlowDown", 0.15f, new ConfigDescription("How much slower time runs after the apparatus is pulled.", (AcceptableValueBase)(object)R(0f, 2f), Array.Empty<object>()));
			LeaveEarlyBoostEnabled = c.Bind<bool>("7. Leave early", "Enabled", true, "When dead players vote for the autopilot to leave early (and every living player is on the ship) time speeds up so the ship takes off much sooner.\nThe inside, the outer catwalks and the roof all count as on the ship. If anyone steps off, time slows back down until they return.");
			LeaveEarlySpeedE = c.Bind<float>("7. Leave early", "Speed", 2f, new ConfigDescription("How fast time runs while the leave-early boost is active. This may exceed MaxSpeed.", (AcceptableValueBase)(object)R(1f, 5f), Array.Empty<object>()));
			EclipsedOverride = c.Bind<bool>("8. Eclipsed", "Enabled", true, "On Eclipsed days, time runs at one fixed speed all day and all other effects are ignored.");
			EclipsedSpeedE = c.Bind<float>("8. Eclipsed", "Speed", 0.7f, new ConfigDescription("The fixed time speed on Eclipsed days. Not limited by MinSpeed or MaxSpeed.", (AcceptableValueBase)(object)R(0.1f, 5f), Array.Empty<object>()));
			Clock24h = c.Bind<bool>("9. Other", "Use24HourClock", true, "Shows the in-game clock in 24-hour format (14:30 instead of 2:30 PM). This is a personal setting and is not taken from the host.");
			DebugLog = c.Bind<bool>("9. Other", "DebugLog", false, "Writes the current speed and the reasons for it to the BepInEx log every 10 seconds. Useful for tuning the settings above.");
			_version = c.Bind<int>("Internal", "ConfigVersion", 1, "Used by the mod to keep your settings up to date. Do not edit.");
			Migrate(c);
			CarryOverMovedSettings(c);
		}

		private void Migrate(ConfigFile c)
		{
			List<string> changed;
			if (_version.Value < 5)
			{
				changed = new List<string>();
				if (_version.Value < 2)
				{
					Move(TransitionStartHourE, 10f);
					Move(TransitionEndHourE, 16f);
					Move(EveningSpeedE, 0.65f);
				}
				if (_version.Value < 3)
				{
					Move(TransitionStartHourE, 9f);
					Move(TransitionEndHourE, 14.5f);
				}
				if (_version.Value < 5)
				{
					Move(TransitionEndHourE, 14f);
				}
				_version.Value = 5;
				c.Save();
				if (changed.Count > 0)
				{
					Plugin.Log.LogInfo((object)("Updated default settings: " + string.Join(", ", changed)));
				}
			}
			void Move(ConfigEntry<float> e, float oldDefault)
			{
				if (Math.Abs(e.Value - oldDefault) < 0.0001f && Math.Abs(e.Value - (float)((ConfigEntryBase)e).DefaultValue) > 0.0001f)
				{
					changed.Add($"{((ConfigEntryBase)e).Definition.Key} {e.Value} → {((ConfigEntryBase)e).DefaultValue}");
					e.Value = (float)((ConfigEntryBase)e).DefaultValue;
				}
			}
		}

		private void CarryOverMovedSettings(ConfigFile c)
		{
			try
			{
				object obj = typeof(ConfigFile).GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(c);
				Dictionary<ConfigDefinition, string> orphans = obj as Dictionary<ConfigDefinition, string>;
				bool changed;
				if (orphans != null && orphans.Count != 0)
				{
					changed = false;
					if (bool.TryParse(Take("9. Clock", "Use24HourClock") ?? "", out var result))
					{
						Clock24h.Value = result;
					}
					if (bool.TryParse(Take("10. Advanced", "DebugLog") ?? "", out var result2))
					{
						DebugLog.Value = result2;
					}
					string s = Take("4. Enemies", "InsideWeight");
					string s2 = Take("4. Enemies", "OutsideWeight");
					if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && float.TryParse(s2, NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) && result3 >= 0f && result4 >= 0f && result3 + result4 > 0f && Math.Abs(result3 - 0.35f) + Math.Abs(result4 - 0.65f) > 0.0001f)
					{
						OutsideShareE.Value = result4 / (result3 + result4);
					}
					(string, string)[] array = new(string, string)[3]
					{
						("7. Leave early", "ShipAreaMargin"),
						("6. Apparatus", "FadeHours"),
						("10. Advanced", "SmoothingSeconds")
					};
					for (int i = 0; i < array.Length; i++)
					{
						(string, string) tuple = array[i];
						Take(tuple.Item1, tuple.Item2);
					}
					if (changed)
					{
						c.Save();
					}
				}
				string Take(string section, string key)
				{
					//IL_0002: Unknown result type (might be due to invalid IL or missing references)
					//IL_0008: Expected O, but got Unknown
					ConfigDefinition key2 = new ConfigDefinition(section, key);
					if (!orphans.TryGetValue(key2, out var value))
					{
						return null;
					}
					orphans.Remove(key2);
					changed = true;
					return value;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Settings carry-over skipped: " + ex.Message));
			}
		}

		private static float Num(ConfigEntry<float> e, float lo, float hi)
		{
			float num = e.Value;
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				num = (float)((ConfigEntryBase)e).DefaultValue;
			}
			if (!(num < lo))
			{
				if (!(num > hi))
				{
					return num;
				}
				return hi;
			}
			return lo;
		}
	}
	internal static class MoonDifficulty
	{
		internal enum Source
		{
			Rated,
			Unknown,
			Override
		}

		internal struct Rating
		{
			public float Score;

			public float MorningSpeed;

			public Source Source;

			public string Note;
		}

		internal const float EasyScore = 20f;

		internal const float NormalScore = 35f;

		internal const float HardScore = 50f;

		private const float UnknownPower = 1f;

		private static readonly HashSet<string> VanillaMoons = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"Experimentation", "Assurance", "Vow", "Gordion", "March", "Adamance", "Rend", "Dine", "Offense", "Titan",
			"Artifice", "Liquidation", "Embrion"
		};

		private static bool _listed;

		private static string _overridesText;

		private static Dictionary<string, float> _overrides = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		public static Rating Rate(SelectableLevel lvl, Config cfg)
		{
			Rating result = new Rating
			{
				Score = float.NaN,
				MorningSpeed = cfg.MorningSpeedNormal,
				Source = Source.Unknown
			};
			if ((Object)(object)lvl == (Object)null)
			{
				result.Note = "no moon";
				return result;
			}
			if (Overrides(cfg).TryGetValue(CleanName(lvl.PlanetName), out var value))
			{
				result.MorningSpeed = value;
				result.Source = Source.Override;
				result.Note = "set in config";
				return result;
			}
			try
			{
				(float power, bool usable) tuple = AveragePower(lvl.Enemies);
				float item = tuple.power;
				bool item2 = tuple.usable;
				(float power, bool usable) tuple2 = AveragePower(lvl.OutsideEnemies);
				float item3 = tuple2.power;
				bool item4 = tuple2.usable;
				bool flag = item2 && lvl.maxEnemyPowerCount > 0;
				bool flag2 = item4 && lvl.maxOutsideEnemyPowerCount > 0;
				if (!flag && !flag2)
				{
					result.Note = "no readable enemy data, treated as an average moon";
					return result;
				}
				float num = (flag ? ((float)lvl.maxEnemyPowerCount * item) : 0f) + (flag2 ? ((float)lvl.maxOutsideEnemyPowerCount * item3) : 0f);
				if (float.IsNaN(num) || float.IsInfinity(num))
				{
					result.Note = "unreadable values, treated as an average moon";
					return result;
				}
				result.Score = num;
				result.MorningSpeed = MorningSpeedFor(num, cfg);
				result.Source = Source.Rated;
				return result;
			}
			catch (Exception ex)
			{
				result.Note = "error (" + ex.Message + "), treated as an average moon";
				return result;
			}
		}

		private static (float power, bool usable) AveragePower(List<SpawnableEnemyWithRarity> list)
		{
			if (list == null)
			{
				return (power: 0f, usable: false);
			}
			float num = 0f;
			float num2 = 0f;
			foreach (SpawnableEnemyWithRarity item in list)
			{
				if (item != null && !((Object)(object)item.enemyType == (Object)null) && item.rarity > 0 && !item.enemyType.spawningDisabled)
				{
					float num3 = item.enemyType.PowerLevel;
					if (float.IsNaN(num3) || num3 <= 0f)
					{
						num3 = 1f;
					}
					num += (float)item.rarity;
					num2 += (float)item.rarity * num3;
				}
			}
			if (!(num > 0f))
			{
				return (power: 0f, usable: false);
			}
			return (power: num2 / num, usable: true);
		}

		public static float MorningSpeedFor(float score, Config cfg)
		{
			if (score <= 20f)
			{
				return cfg.MorningSpeedEasy;
			}
			if (score <= 35f)
			{
				return Mathf.Lerp(cfg.MorningSpeedEasy, cfg.MorningSpeedNormal, (score - 20f) / 15f);
			}
			if (score <= 50f)
			{
				return Mathf.Lerp(cfg.MorningSpeedNormal, cfg.MorningSpeed, (score - 35f) / 15f);
			}
			return cfg.MorningSpeed;
		}

		public static string CleanName(string planetName)
		{
			string text = (planetName ?? "").Trim();
			int num = text.IndexOf(' ');
			if (num > 0 && char.IsDigit(text[0]))
			{
				text = text.Substring(num + 1).Trim();
			}
			return text;
		}

		public static bool IsVanilla(SelectableLevel lvl)
		{
			return VanillaMoons.Contains(CleanName(lvl?.PlanetName));
		}

		private static Dictionary<string, float> Overrides(Config cfg)
		{
			string text = cfg.MorningSpeedOverrides.Value ?? "";
			if (text == _overridesText)
			{
				return _overrides;
			}
			_overridesText = text;
			Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
			string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text2 in array)
			{
				int num = text2.IndexOf('=');
				if (num <= 0)
				{
					Plugin.Log.LogWarning((object)("MorningSpeedOverrides: ignored \"" + text2.Trim() + "\" (expected Moon=speed)"));
					continue;
				}
				string key = CleanName(text2.Substring(0, num));
				if (float.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result >= 0.1f && result <= 5f)
				{
					dictionary[key] = result;
				}
				else
				{
					Plugin.Log.LogWarning((object)("MorningSpeedOverrides: ignored \"" + text2.Trim() + "\" (speed must be a number from 0.1 to 5)"));
				}
			}
			_overrides = dictionary;
			return dictionary;
		}

		public static void ListAllMoonsOnce()
		{
			if (_listed)
			{
				return;
			}
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null) && instance.levels != null && instance.levels.Length != 0)
			{
				_listed = true;
				Config cfg = Plugin.Cfg;
				IEnumerable<string> values = (from l in instance.levels
					where (Object)(object)l != (Object)null && l.planetHasTime && l.spawnEnemiesAndScrap
					select (lvl: l, r: Rate(l, cfg)) into x
					orderby (!float.IsNaN(x.r.Score)) ? x.r.Score : float.MaxValue
					select x).Select(delegate((SelectableLevel lvl, Rating r) x)
				{
					SelectableLevel item = x.lvl;
					string text = $"inside {item.maxEnemyPowerCount} x {AveragePower(item.Enemies).power:0.00}, outside {item.maxOutsideEnemyPowerCount} x {AveragePower(item.OutsideEnemies).power:0.00}";
					string text2 = ((x.r.Source == Source.Rated) ? $"score {x.r.Score,6:0.0}" : "score    -  ");
					string text3 = ((x.r.Note != null) ? ("  [" + x.r.Note + "]") : "");
					return string.Format("  {0,-22} {1,-8} {2}  ({3})  -> morning {4:0.00}x{5}", CleanName(item.PlanetName), IsVanilla(item) ? "vanilla" : "modded ", text2, text, x.r.MorningSpeed, text3);
				});
				Plugin.Log.LogInfo((object)("Moon difficulty (used for the morning speed). Moons' enemy lists can still change when landing, so the speed actually used is worked out again at the start of each day:\n" + string.Join("\n", values)));
			}
		}
	}
	internal static class Net
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnSpeed;
		}

		private const string MsgName = "slivkonsin.DynamicLongerDays.Speed";

		private const float SendInterval = 0.25f;

		private const float FreshSeconds = 3f;

		public static float HostSpeed = 1f;

		private static float _hostSpeedAt = -100f;

		private static CustomMessagingManager _registered;

		private static float _nextSend;

		private static bool _warnedNoHost;

		public static bool IsAuthority
		{
			get
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (!((Object)(object)singleton == (Object)null) && singleton.IsListening)
				{
					return singleton.IsServer;
				}
				return true;
			}
		}

		public static bool HostSpeedFresh => Time.realtimeSinceStartup - _hostSpeedAt < 3f;

		public unsafe static void Update()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null)
			{
				_registered = null;
				_warnedNoHost = false;
				return;
			}
			if (_registered != singleton.CustomMessagingManager)
			{
				_registered = singleton.CustomMessagingManager;
				CustomMessagingManager registered = _registered;
				object obj = <>O.<0>__OnSpeed;
				if (obj == null)
				{
					HandleNamedMessageDelegate val = OnSpeed;
					<>O.<0>__OnSpeed = val;
					obj = (object)val;
				}
				registered.RegisterNamedMessageHandler("slivkonsin.DynamicLongerDays.Speed", (HandleNamedMessageDelegate)obj);
				_hostSpeedAt = -100f;
			}
			if (singleton.IsServer)
			{
				if (!DiagnosticsTelemetry.Active || Time.realtimeSinceStartup < _nextSend)
				{
					return;
				}
				_nextSend = Time.realtimeSinceStartup + 0.25f;
				if (singleton.ConnectedClientsIds.Count <= 1)
				{
					return;
				}
				try
				{
					FastBufferWriter val2 = default(FastBufferWriter);
					((FastBufferWriter)(ref val2))..ctor(4, (Allocator)2, -1);
					try
					{
						((FastBufferWriter)(ref val2)).WriteValueSafe<float>(ref SpeedController.Applied, default(ForPrimitives));
						_registered.SendNamedMessageToAll("slivkonsin.DynamicLongerDays.Speed", val2, (NetworkDelivery)0);
						return;
					}
					finally
					{
						((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose();
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Could not send time speed: " + ex.Message));
					return;
				}
			}
			if (!_warnedNoHost && DiagnosticsTelemetry.ClockHour > 0f && !HostSpeedFresh && (Object)(object)StartOfRound.Instance != (Object)null && !StartOfRound.Instance.inShipPhase && (Object)(object)TimeOfDay.Instance != (Object)null && TimeOfDay.Instance.currentDayTimeStarted && Time.realtimeSinceStartup - _hostSpeedAt > 15f)
			{
				_warnedNoHost = true;
				Plugin.Log.LogWarning((object)"No time speed received from the host — the host probably doesn't have Dynamic Longer Days. Using vanilla speed.");
			}
		}

		private static void OnSpeed(ulong sender, FastBufferReader reader)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				float num = default(float);
				((FastBufferReader)(ref reader)).ReadValueSafe<float>(ref num, default(ForPrimitives));
				if (!float.IsNaN(num) && !(num <= 0f) && !(num > 20f))
				{
					HostSpeed = num;
					_hostSpeedAt = Time.realtimeSinceStartup;
				}
			}
			catch
			{
			}
		}
	}
	internal static class Patches
	{
		public static bool TimeHooked;

		public static bool ClockHooked;

		public static void Install(Harmony h)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_0096: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(TimeOfDay), "MoveGlobalTime", (Type[])null, (Type[])null);
			FieldInfo fieldInfo = AccessTools.Field(typeof(TimeOfDay), "globalTimeSpeedMultiplier");
			if (methodInfo == null || fieldInfo == null)
			{
				Plugin.Log.LogError((object)"TimeOfDay.MoveGlobalTime / globalTimeSpeedMultiplier not found (game update?). Dynamic Longer Days is inactive; days run at vanilla speed.");
			}
			else
			{
				try
				{
					h.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "MovePrefix", (Type[])null)
					{
						priority = 0
					}, new HarmonyMethod(typeof(Patches), "MovePostfix", (Type[])null)
					{
						priority = 800
					}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					TimeHooked = true;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Could not hook the game clock: " + ex));
				}
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(HUDManager), "SetClock", (Type[])null, (Type[])null);
			MethodInfo methodInfo3 = AccessTools.Method(typeof(HUDManager), "GetClockTimeFormatted", (Type[])null, (Type[])null);
			try
			{
				if (methodInfo2 != null)
				{
					h.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "SetClockPostfix", (Type[])null)
					{
						priority = 0
					}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					ClockHooked = true;
				}
				if (methodInfo3 != null)
				{
					h.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "FormattedPostfix", (Type[])null)
					{
						priority = 0
					}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("24-hour clock unavailable: " + ex2.Message));
			}
		}

		private static void MovePrefix(TimeOfDay __instance, out float __state)
		{
			__state = __instance.globalTimeSpeedMultiplier;
			float applied = SpeedController.Applied;
			if (applied > 0f && Math.Abs(applied - 1f) > 0.0001f)
			{
				__instance.globalTimeSpeedMultiplier = __state * applied;
			}
		}

		private static void MovePostfix(TimeOfDay __instance, float __state)
		{
			__instance.globalTimeSpeedMultiplier = __state;
		}

		private static void SetClockPostfix(HUDManager __instance, float timeNormalized, float numberOfHours, bool createNewLine)
		{
			if (!Plugin.Cfg.Clock24h.Value || (Object)(object)__instance == (Object)null || (Object)(object)__instance.clockNumber == (Object)null)
			{
				return;
			}
			try
			{
				((TMP_Text)__instance.clockNumber).text = Format24(timeNormalized, numberOfHours);
			}
			catch
			{
			}
		}

		private static void FormattedPostfix(float timeNormalized, float numberOfHours, ref string __result)
		{
			if (!Plugin.Cfg.Clock24h.Value)
			{
				return;
			}
			try
			{
				__result = Format24(timeNormalized, numberOfHours);
			}
			catch
			{
			}
		}

		private static string Format24(float timeNormalized, float numberOfHours)
		{
			int num = (int)(timeNormalized * (60f * numberOfHours)) + 360;
			if (num >= 1440)
			{
				return "24:00";
			}
			return $"{num / 60:00}:{num % 60:00}";
		}
	}
	[BepInPlugin("slivkonsin.DynamicLongerDays", "Dynamic Longer Days", "1.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "slivkonsin.DynamicLongerDays";

		public const string Name = "Dynamic Longer Days";

		public const string Version = "1.1.0";

		private const string LongerDaysGuid = "ElecTRiCbOi59.LongerDays";

		internal static ManualLogSource Log;

		internal static Config Cfg;

		private static Harmony _harmony;

		private static bool _compatDone;

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new Config(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("slivkonsin.DynamicLongerDays");
			Patches.Install(_harmony);
			GameObject val = new GameObject("DynamicLongerDays");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<Runner>();
			SceneManager.sceneLoaded += OnSceneLoaded;
			Log.LogInfo((object)("Dynamic Longer Days 1.1.0 loaded (clock hook: " + (Patches.TimeHooked ? "ok" : "MISSING") + ", 24h clock: " + (Patches.ClockHooked ? "ok" : "unavailable") + ")."));
		}

		private static void OnSceneLoaded(Scene s, LoadSceneMode m)
		{
			if (_compatDone)
			{
				return;
			}
			_compatDone = true;
			try
			{
				TakeOverFromLongerDays();
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("LongerDays compatibility step failed: " + ex.Message));
			}
		}

		private static void TakeOverFromLongerDays()
		{
			if (!Chainloader.PluginInfos.ContainsKey("ElecTRiCbOi59.LongerDays"))
			{
				return;
			}
			int num = 0;
			(Type, string)[] array = new(Type, string)[2]
			{
				(typeof(TimeOfDay), "MoveTimeOfDay"),
				(typeof(HUDManager), "SetClock")
			};
			for (int i = 0; i < array.Length; i++)
			{
				(Type, string) tuple = array[i];
				Type item = tuple.Item1;
				string item2 = tuple.Item2;
				MethodInfo methodInfo = AccessTools.Method(item, item2, (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
					if (patchInfo != null && patchInfo.Owners.Contains("ElecTRiCbOi59.LongerDays"))
					{
						_harmony.Unpatch((MethodBase)methodInfo, (HarmonyPatchType)0, "ElecTRiCbOi59.LongerDays");
						num++;
					}
				}
			}
			Log.LogWarning((object)((num > 0) ? $"LongerDays is installed: Dynamic Longer Days takes over day speed and clock text (removed {num} of its patches). Its clock layout options still work." : "LongerDays is installed but none of its time patches were found; nothing changed."));
		}
	}
	internal sealed class Runner : MonoBehaviour
	{
		private void Update()
		{
			try
			{
				Net.Update();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Network: " + ex.Message));
			}
			try
			{
				MoonDifficulty.ListAllMoonsOnce();
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogDebug((object)("Moon list: " + ex2.Message));
			}
			try
			{
				SpeedController.Update();
			}
			catch (Exception ex3)
			{
				SpeedController.Applied = 1f;
				Plugin.Log.LogWarning((object)("Speed update failed, using vanilla speed this frame: " + ex3.Message));
			}
		}
	}
	public static class DiagnosticsTelemetry
	{
		public static bool Active;

		public static float Speed = 1f;

		public static float Target = 1f;

		public static float Baseline = 1f;

		public static float EnemyEffect;

		public static float ApparatusEffect;

		public static float DeadPlayerEffect;

		public static int DeadPlayers;

		public static int Players;

		public static bool LeaveEarlyVoted;

		public static bool LeaveEarlyBoost;

		public static int AlivePlayers;

		public static int AliveOnShip;

		public static float Danger;

		public static float InsideDanger;

		public static float OutsideDanger;

		public static float ClockHour;

		public static bool Eclipsed;

		public static bool FromHost;

		public static float MoonScore;

		public static float MorningSpeed;
	}
	internal static class SpeedController
	{
		public static float Applied = 1f;

		private static float _smoothed = 1f;

		private static bool _wasRunning;

		private static double _nextEval;

		private static double _nextLog;

		private static readonly Dictionary<int, bool> ApparatusDocked = new Dictionary<int, bool>();

		private static double _nextApparatusScan;

		private static float _apparatusPulledAtHour = -1f;

		private static readonly HashSet<ulong> DeadThisRound = new HashSet<ulong>();

		private static int _maxPlayersThisRound;

		private static float _morningSpeed = -1f;

		public static bool HasEnemyData = true;

		public static bool HasApparatusData = true;

		public static bool HasPlayerData = true;

		public static bool HasShipData = true;

		private static Config Cfg => Plugin.Cfg;

		private static bool DayRunning(out TimeOfDay tod)
		{
			tod = TimeOfDay.Instance;
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)tod == (Object)null || (Object)(object)instance == (Object)null || instance.inShipPhase || !tod.currentDayTimeStarted)
			{
				return false;
			}
			SelectableLevel currentLevel = instance.currentLevel;
			if ((Object)(object)currentLevel != (Object)null)
			{
				return currentLevel.planetHasTime;
			}
			return false;
		}

		public static void Update()
		{
			if (!DayRunning(out var tod) || !Cfg.Enabled.Value)
			{
				if (_wasRunning)
				{
					EndDay();
				}
				Applied = 1f;
				DiagnosticsTelemetry.Active = false;
				return;
			}
			if (!_wasRunning)
			{
				StartDay();
			}
			if (!Net.IsAuthority)
			{
				Applied = (Net.HostSpeedFresh ? Net.HostSpeed : 1f);
				DiagnosticsTelemetry.Active = Net.HostSpeedFresh;
				DiagnosticsTelemetry.FromHost = true;
				DiagnosticsTelemetry.Speed = Applied;
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if ((double)realtimeSinceStartup >= _nextEval)
			{
				_nextEval = realtimeSinceStartup + 0.25f;
				Evaluate(tod);
			}
			float smoothingSeconds = Cfg.SmoothingSeconds;
			_smoothed += (DiagnosticsTelemetry.Target - _smoothed) * (1f - Mathf.Exp((0f - Time.deltaTime) / smoothingSeconds));
			Applied = _smoothed;
			DiagnosticsTelemetry.Speed = Applied;
			DiagnosticsTelemetry.Active = true;
			DiagnosticsTelemetry.FromHost = false;
			if (Cfg.DebugLog.Value && (double)realtimeSinceStartup >= _nextLog)
			{
				_nextLog = realtimeSinceStartup + 10f;
				string text = (DiagnosticsTelemetry.Eclipsed ? "eclipsed" : ($"base {DiagnosticsTelemetry.Baseline:0.00} enemies {DiagnosticsTelemetry.EnemyEffect:+0.00;-0.00} (danger {DiagnosticsTelemetry.Danger:P0}: in {DiagnosticsTelemetry.InsideDanger:P0} out {DiagnosticsTelemetry.OutsideDanger:P0}) apparatus {DiagnosticsTelemetry.ApparatusEffect:+0.00;-0.00} deaths {DiagnosticsTelemetry.DeadPlayers}/{DiagnosticsTelemetry.Players} {DiagnosticsTelemetry.DeadPlayerEffect:+0.00;-0.00}" + (DiagnosticsTelemetry.LeaveEarlyBoost ? " LEAVE-EARLY BOOST" : (DiagnosticsTelemetry.LeaveEarlyVoted ? $" (leave-early voted, {DiagnosticsTelemetry.AliveOnShip}/{DiagnosticsTelemetry.AlivePlayers} on ship)" : ""))));
				Plugin.Log.LogInfo((object)$"{FormatHour(DiagnosticsTelemetry.ClockHour)} speed {Applied:0.00}x → {DiagnosticsTelemetry.Target:0.00}x ({text})");
			}
		}

		private static void StartDay()
		{
			_wasRunning = true;
			ApparatusDocked.Clear();
			_apparatusPulledAtHour = -1f;
			_nextApparatusScan = 0.0;
			DeadThisRound.Clear();
			_maxPlayersThisRound = 0;
			_morningSpeed = -1f;
			if (Net.IsAuthority && DayRunning(out var tod))
			{
				Evaluate(tod);
				_smoothed = DiagnosticsTelemetry.Target;
			}
		}

		private static void EndDay()
		{
			_wasRunning = false;
			_smoothed = 1f;
		}

		private static void Evaluate(TimeOfDay tod)
		{
			StartOfRound sor = StartOfRound.Instance;
			DiagnosticsTelemetry.Target = NormalTarget(hour: DiagnosticsTelemetry.ClockHour = 6f + tod.normalizedTimeOfDay * (float)tod.numberOfHours, sor: sor);
			if (DiagnosticsTelemetry.LeaveEarlyBoost = Cfg.LeaveEarlyBoostEnabled.Value && HasShipData && Safe(() => (!LeaveEarlyApplies(tod, sor)) ? 0f : 1f, 0f, ref HasShipData) > 0.5f)
			{
				DiagnosticsTelemetry.Target = Mathf.Max(DiagnosticsTelemetry.Target, Cfg.LeaveEarlySpeed);
			}
		}

		private static float NormalTarget(StartOfRound sor, float hour)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			if (DiagnosticsTelemetry.Eclipsed = Cfg.EclipsedOverride.Value && (int)sor.currentLevel.currentWeather == 5)
			{
				DiagnosticsTelemetry.Baseline = Cfg.EclipsedSpeed;
				DiagnosticsTelemetry.EnemyEffect = (DiagnosticsTelemetry.ApparatusEffect = (DiagnosticsTelemetry.DeadPlayerEffect = 0f));
				return Cfg.EclipsedSpeed;
			}
			float num = Baseline(hour);
			float num2 = ((Cfg.EnemyEffectEnabled.Value && HasEnemyData) ? Safe(EnemyEffect, 0f, ref HasEnemyData) : 0f);
			float num3 = ((Cfg.ApparatusEffectEnabled.Value && HasApparatusData) ? Safe(() => ApparatusEffect(hour), 0f, ref HasApparatusData) : 0f);
			float num4 = ((Cfg.DeadPlayerEffectEnabled.Value && HasPlayerData) ? Safe(DeadPlayerEffect, 0f, ref HasPlayerData) : 0f);
			DiagnosticsTelemetry.Baseline = num;
			DiagnosticsTelemetry.EnemyEffect = num2;
			DiagnosticsTelemetry.ApparatusEffect = num3;
			DiagnosticsTelemetry.DeadPlayerEffect = num4;
			float num5 = num + num2 + num3 + num4;
			if (float.IsNaN(num5) || float.IsInfinity(num5))
			{
				num5 = 1f;
			}
			return Mathf.Clamp(num5, Cfg.MinSpeed, Cfg.MaxSpeed);
		}

		private static bool LeaveEarlyApplies(TimeOfDay tod, StartOfRound sor)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			bool flag = (DiagnosticsTelemetry.LeaveEarlyVoted = tod.votesForShipToLeaveEarly > 0 && tod.shipLeaveAutomaticallyTime < 0.99f);
			int num = 0;
			int num2 = 0;
			if (flag && sor.allPlayerScripts != null && !sor.shipIsLeaving)
			{
				Bounds val = default(Bounds);
				bool flag2 = (Object)(object)sor.shipBounds != (Object)null;
				if (flag2)
				{
					val = sor.shipBounds.bounds;
					((Bounds)(ref val)).Expand(Cfg.ShipAreaMargin * 2f);
				}
				PlayerControllerB[] allPlayerScripts = sor.allPlayerScripts;
				foreach (PlayerControllerB val2 in allPlayerScripts)
				{
					if (!((Object)(object)val2 == (Object)null) && val2.isPlayerControlled && !val2.isPlayerDead)
					{
						num++;
						if (val2.isInHangarShipRoom || val2.isInElevator || (flag2 && ((Bounds)(ref val)).Contains(((Component)val2).transform.position)))
						{
							num2++;
						}
					}
				}
			}
			DiagnosticsTelemetry.AlivePlayers = num;
			DiagnosticsTelemetry.AliveOnShip = num2;
			if (flag && num > 0)
			{
				return num2 == num;
			}
			return false;
		}

		private static float Safe(Func<float> f, float fallback, ref bool available)
		{
			try
			{
				float num = f();
				return (float.IsNaN(num) || float.IsInfinity(num)) ? fallback : num;
			}
			catch (Exception ex)
			{
				available = false;
				Plugin.Log.LogWarning((object)("Disabled a speed factor after an error (game update?): " + ex.Message));
				return fallback;
			}
		}

		private static float DeadPlayerEffect()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null)
			{
				return 0f;
			}
			int num = 0;
			PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && (val.isPlayerControlled || val.isPlayerDead))
				{
					num++;
					if (val.isPlayerDead)
					{
						DeadThisRound.Add(val.playerClientId);
					}
					else if (Cfg.RevivesRemovePenalty.Value)
					{
						DeadThisRound.Remove(val.playerClientId);
					}
				}
			}
			_maxPlayersThisRound = Math.Max(_maxPlayersThisRound, num);
			int num2 = (DiagnosticsTelemetry.Players = Math.Max(1, _maxPlayersThisRound));
			DiagnosticsTelemetry.DeadPlayers = DeadThisRound.Count;
			return (0f - Cfg.DeadPlayersMaxSlowDown) * (float)Math.Min(DeadThisRound.Count, num2) / (float)num2;
		}

		public static float Baseline(float hour)
		{
			float transitionStartHour = Cfg.TransitionStartHour;
			float transitionEndHour = Cfg.TransitionEndHour;
			float num = TodaysMorningSpeed();
			float eveningSpeed = Cfg.EveningSpeed;
			if (transitionEndHour <= transitionStartHour)
			{
				if (!(hour < transitionStartHour))
				{
					return eveningSpeed;
				}
				return num;
			}
			if (hour <= transitionStartHour)
			{
				return num;
			}
			if (hour >= transitionEndHour)
			{
				return eveningSpeed;
			}
			return Mathf.Lerp(num, eveningSpeed, (hour - transitionStartHour) / (transitionEndHour - transitionStartHour));
		}

		private static float TodaysMorningSpeed()
		{
			if (!Cfg.MoonDifficultyEnabled.Value)
			{
				return Cfg.MorningSpeed;
			}
			if (_morningSpeed < 0f)
			{
				_morningSpeed = Cfg.MorningSpeedNormal;
				try
				{
					SelectableLevel val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.currentLevel : null);
					MoonDifficulty.Rating rating = MoonDifficulty.Rate(val, Cfg);
					_morningSpeed = rating.MorningSpeed;
					DiagnosticsTelemetry.MoonScore = (float.IsNaN(rating.Score) ? (-1f) : rating.Score);
					string arg = ((rating.Source == MoonDifficulty.Source.Rated) ? $"difficulty {rating.Score:0.0}" : rating.Note);
					if (rating.Source == MoonDifficulty.Source.Unknown)
					{
						Plugin.Log.LogInfo((object)$"{val?.PlanetName}: {arg}. Morning speed {_morningSpeed:0.00}x (can be set with MorningSpeedOverrides).");
					}
					else if (Cfg.DebugLog.Value)
					{
						Plugin.Log.LogInfo((object)$"{val?.PlanetName}: {arg}, morning speed {_morningSpeed:0.00}x");
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Could not rate this moon, using MorningSpeedNormal: " + ex.Message));
				}
				DiagnosticsTelemetry.MorningSpeed = _morningSpeed;
			}
			return _morningSpeed;
		}

		private static float EnemyEffect()
		{
			RoundManager instance = RoundManager.Instance;
			if ((Object)(object)instance == (Object)null || instance.SpawnedEnemies == null)
			{
				return 0f;
			}
			float num = 0f;
			float num2 = 0f;
			foreach (EnemyAI spawnedEnemy in instance.SpawnedEnemies)
			{
				if (!((Object)(object)spawnedEnemy == (Object)null) && !spawnedEnemy.isEnemyDead && !((Object)(object)spawnedEnemy.enemyType == (Object)null) && !spawnedEnemy.enemyType.isDaytimeEnemy)
				{
					if (spawnedEnemy.isOutside)
					{
						num2 += spawnedEnemy.enemyType.PowerLevel;
					}
					else
					{
						num += spawnedEnemy.enemyType.PowerLevel;
					}
				}
			}
			float currentMaxInsidePower = instance.currentMaxInsidePower;
			float currentMaxOutsidePower = instance.currentMaxOutsidePower;
			float num3 = ((currentMaxInsidePower > 0f) ? Mathf.Clamp01(num / currentMaxInsidePower) : 0f);
			float num4 = ((currentMaxOutsidePower > 0f) ? Mathf.Clamp01(num2 / currentMaxOutsidePower) : 0f);
			float num5 = ((currentMaxInsidePower > 0f) ? Mathf.Max(0f, Cfg.InsideWeight) : 0f);
			float num6 = ((currentMaxOutsidePower > 0f) ? Mathf.Max(0f, Cfg.OutsideWeight) : 0f);
			float num7 = ((num5 + num6 > 0f) ? ((num3 * num5 + num4 * num6) / (num5 + num6)) : 0f);
			DiagnosticsTelemetry.InsideDanger = num3;
			DiagnosticsTelemetry.OutsideDanger = num4;
			DiagnosticsTelemetry.Danger = num7;
			float num8 = Mathf.Clamp(Cfg.NeutralDanger, 0.001f, 0.999f);
			if (!(num7 < num8))
			{
				return (0f - Cfg.MaxSlowDown) * ((num7 - num8) / (1f - num8));
			}
			return Cfg.MaxSpeedUp * (1f - num7 / num8);
		}

		private static float ApparatusEffect(float hour)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if ((double)realtimeSinceStartup >= _nextApparatusScan)
			{
				_nextApparatusScan = realtimeSinceStartup + 1f;
				LungProp[] array = Object.FindObjectsByType<LungProp>((FindObjectsSortMode)0);
				foreach (LungProp val in array)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					int instanceID = ((Object)val).GetInstanceID();
					bool isLungDocked = val.isLungDocked;
					if (ApparatusDocked.TryGetValue(instanceID, out var value) && value && !isLungDocked && _apparatusPulledAtHour < 0f)
					{
						_apparatusPulledAtHour = hour;
						if (Cfg.DebugLog.Value)
						{
							Plugin.Log.LogInfo((object)("Apparatus pulled at " + FormatHour(hour) + ": slowing time."));
						}
					}
					ApparatusDocked[instanceID] = isLungDocked;
				}
			}
			if (!(_apparatusPulledAtHour < 0f))
			{
				return 0f - Cfg.ApparatusSlowDown;
			}
			return 0f;
		}

		public static string FormatHour(float hour)
		{
			int num = Mathf.FloorToInt(hour * 60f);
			return $"{num / 60 % 24:00}:{num % 60:00}";
		}
	}
}