Decompiled source of WeatherGordion v1.0.5

WeatherGordion.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MrovLib;
using MrovLib.Events;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
using WeatherGordion.Compat;
using WeatherGordion.Patches;
using WeatherRegistry;
using WeatherRegistry.Definitions;
using WeatherRegistry.Utils;

[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("WeatherGordion")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: AssemblyInformationalVersion("1.0.5+42422f8619b0c4f5b2c073a4808bb374772470b6")]
[assembly: AssemblyProduct("WeatherGordion")]
[assembly: AssemblyTitle("WeatherGordion")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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 WeatherGordion
{
	internal static class ClockOverlay
	{
		private static bool _loggedState;

		public static void Draw(float normalizedTimeOfDay)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Cfg.ShowClock.Value)
			{
				return;
			}
			HUDManager instance = HUDManager.Instance;
			TimeOfDay instance2 = TimeOfDay.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null)
			{
				return;
			}
			instance.SetClockVisible(true);
			instance.SetClock(normalizedTimeOfDay, (float)instance2.numberOfHours, true);
			instance.SetClockIcon(instance2.dayMode);
			CanvasGroup val = instance.Clock?.canvasGroup;
			if ((Object)(object)val == (Object)null)
			{
				LogStateOnce("HUDManager.Clock has no canvas group — the clock cannot be shown.");
				return;
			}
			if (!((Component)val).gameObject.activeSelf)
			{
				((Component)val).gameObject.SetActive(true);
			}
			val.alpha = 1f;
			string text = $"Clock asserted: active {((Component)val).gameObject.activeInHierarchy}, alpha {val.alpha:0.##}, ";
			object arg = instance2.numberOfHours;
			TextMeshProUGUI clockNumber = instance.clockNumber;
			LogStateOnce(text + $"numberOfHours {arg}, text '{((clockNumber != null) ? ((TMP_Text)clockNumber).text : null)}'.");
		}

		public static void Hide()
		{
			_loggedState = false;
			if (!Plugin.Cfg.ShowClock.Value)
			{
				return;
			}
			HUDManager instance = HUDManager.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				instance.SetClockVisible(false);
			}
			catch
			{
			}
		}

		private static void LogStateOnce(string message)
		{
			if (!_loggedState)
			{
				_loggedState = true;
				Plugin.DebugLog(message);
			}
		}
	}
	internal static class GordionLevel
	{
		private static readonly string[] CompanyAliases = new string[4] { "gordion", "71gordion", "companybuilding", "company" };

		private static SelectableLevel _level;

		public static SelectableLevel Level => _level;

		public static bool OriginalPlanetHasTime { get; private set; }

		public static void Resolve(StartOfRound round)
		{
			if ((Object)(object)_level != (Object)null)
			{
				return;
			}
			SelectableLevel[] array = round?.levels;
			if (array != null && array.Length != 0)
			{
				SelectableLevel val = FindByName(array) ?? FindByShape(array);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"Could not find the Company building among the moons — weather on Gordion is disabled for this session. If a moon loader renamed it, that is the likely cause.");
					return;
				}
				_level = val;
				OriginalPlanetHasTime = val.planetHasTime;
				string text = $"Company moon resolved: '{val.PlanetName}' (scene '{val.sceneName}', levelID {val.levelID}, ";
				object arg = val.planetHasTime;
				RandomWeatherWithVariables[] randomWeathers = val.randomWeathers;
				Plugin.DebugLog(text + $"planetHasTime {arg}, randomWeathers {((randomWeathers != null) ? randomWeathers.Length : 0)}).");
			}
		}

		public static void Reset()
		{
			_level = null;
		}

		public static bool Is(SelectableLevel level)
		{
			if ((Object)(object)level != (Object)null)
			{
				return level == _level;
			}
			return false;
		}

		public static bool IsCurrent()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				return Is(instance.currentLevel);
			}
			return false;
		}

		private static SelectableLevel FindByName(SelectableLevel[] levels)
		{
			string[] companyAliases = CompanyAliases;
			foreach (string text in companyAliases)
			{
				foreach (SelectableLevel val in levels)
				{
					if (!((Object)(object)val == (Object)null) && (Normalize(val.PlanetName) == text || Normalize(val.sceneName) == text || Normalize(((Object)val).name) == text))
					{
						return val;
					}
				}
			}
			return null;
		}

		private static SelectableLevel FindByShape(SelectableLevel[] levels)
		{
			foreach (SelectableLevel val in levels)
			{
				if ((Object)(object)val != (Object)null && !val.planetHasTime && !val.spawnEnemiesAndScrap)
				{
					Plugin.Log.LogInfo((object)("No moon matched a Company name; using '" + val.PlanetName + "' (no day cycle, nothing spawns) as the Company building."));
					return val;
				}
			}
			return null;
		}

		public static string Normalize(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return string.Empty;
			}
			int i;
			for (i = 0; i < name.Length && char.IsDigit(name[i]); i++)
			{
			}
			if (i >= name.Length)
			{
				i = 0;
			}
			StringBuilder stringBuilder = new StringBuilder(name.Length - i);
			for (int j = i; j < name.Length; j++)
			{
				char c = name[j];
				if (c != ' ' && c != '-' && c != '_')
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}

		public static string ConfigKey(SelectableLevel level)
		{
			if ((Object)(object)level == (Object)null)
			{
				return string.Empty;
			}
			try
			{
				string alphanumericName = LevelHelper.GetAlphanumericName(level);
				if (!string.IsNullOrEmpty(alphanumericName))
				{
					return alphanumericName;
				}
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("MrovLib.LevelHelper.GetAlphanumericName failed (" + ex.Message + "); falling back.");
			}
			string text = level.PlanetName ?? ((Object)level).name ?? string.Empty;
			StringBuilder stringBuilder = new StringBuilder(text.Length);
			int i;
			for (i = 0; i < text.Length && char.IsDigit(text[i]); i++)
			{
			}
			if (i >= text.Length)
			{
				i = 0;
			}
			for (int j = i; j < text.Length; j++)
			{
				char c = text[j];
				if (c != ' ' && c != '-' && c != '_' && c != '/' && c != '\\')
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal sealed class LandingWatcher : MonoBehaviour
	{
		private const float PollInterval = 0.5f;

		private const float FallbackLandedAfter = 20f;

		private float _nextPoll;

		private bool _landedHandled;

		private float _fallbackTimer;

		internal static void Create()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("WeatherGordion_LandingWatcher");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<LandingWatcher>();
		}

		private void Update()
		{
			if (Time.unscaledTime < _nextPoll)
			{
				return;
			}
			_nextPoll = Time.unscaledTime + 0.5f;
			try
			{
				Poll();
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("LandingWatcher poll failed: " + ex.Message);
			}
		}

		private void Poll()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				if (_landedHandled)
				{
					_landedHandled = false;
					TimeController.OnLeftGordion();
				}
				_fallbackTimer = 0f;
				return;
			}
			if (!GordionLevel.IsCurrent())
			{
				if (_landedHandled)
				{
					_landedHandled = false;
					TimeController.OnLeftGordion();
				}
				_fallbackTimer = 0f;
				return;
			}
			bool flag = instance.shipHasLanded && !instance.shipIsLeaving;
			if (!flag && !instance.shipIsLeaving && !instance.inShipPhase && IsCompanySceneLoaded())
			{
				_fallbackTimer += 0.5f;
				if (_fallbackTimer >= 20f && !_landedHandled)
				{
					Plugin.Log.LogWarning((object)"shipHasLanded was never set (another mod likely altered the landing sequence) — starting the Gordion clock via fallback detection.");
					flag = true;
				}
			}
			else
			{
				_fallbackTimer = 0f;
			}
			if (flag && !_landedHandled)
			{
				_landedHandled = true;
				TimeController.OnLandedOnGordion();
			}
			else if (!flag && _landedHandled && (instance.shipIsLeaving || !instance.shipHasLanded))
			{
				_landedHandled = false;
				_fallbackTimer = 0f;
				TimeController.OnLeftGordion();
			}
		}

		private static bool IsCompanySceneLoaded()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			SelectableLevel level = GordionLevel.Level;
			if ((Object)(object)level == (Object)null || string.IsNullOrEmpty(level.sceneName))
			{
				return false;
			}
			Scene sceneByName = SceneManager.GetSceneByName(level.sceneName);
			if (((Scene)(ref sceneByName)).IsValid())
			{
				return ((Scene)(ref sceneByName)).isLoaded;
			}
			return false;
		}
	}
	[BepInPlugin("Timofey.WeatherGordion", "WeatherGordion", "1.0.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static PluginConfig Cfg { get; private set; }

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Cfg = new PluginConfig(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("Timofey.WeatherGordion");
			_harmony.PatchAll(typeof(StartOfRoundPatches));
			_harmony.PatchAll(typeof(SetPlanetsWeatherPatch));
			_harmony.PatchAll(typeof(RoundManagerPatches));
			_harmony.PatchAll(typeof(TimeOfDayPatches));
			WeatherUnlocker.Subscribe();
			LandingWatcher.Create();
			Log.LogInfo((object)("WeatherGordion v1.0.5 loaded. Weather on 71-Gordion: " + (Cfg.Enabled.Value ? "on" : "off") + ", " + $"time mode: {Cfg.TimeMode.Value}."));
		}

		internal static void DebugLog(string message)
		{
			if (Cfg != null && Cfg.DebugMode.Value)
			{
				Log.LogInfo((object)("[Debug] " + message));
			}
		}

		private void OnDestroy()
		{
			TimeController.RestoreImmediately();
			WeatherUnlocker.Unsubscribe();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal enum GordionTimeMode
	{
		Off,
		RealTime,
		Simulated
	}
	internal sealed class PluginConfig
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<bool> DebugMode;

		public readonly ConfigEntry<string> WeatherWeights;

		public readonly ConfigEntry<int> ClearWeatherWeight;

		public readonly ConfigEntry<bool> RespectExistingConfig;

		public readonly ConfigEntry<GordionTimeMode> TimeMode;

		public readonly ConfigEntry<bool> FreezeDeadline;

		public readonly ConfigEntry<bool> ShipLeavesAtEndOfDay;

		public readonly ConfigEntry<bool> ShowClock;

		public readonly ConfigEntry<float> DayLengthSeconds;

		private Dictionary<string, int> _weights;

		private string _weightsSource;

		public PluginConfig(ConfigFile cfg)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("1. General", "Enabled", true, "Master switch. When off the plugin changes nothing and Gordion stays clear.");
			DebugMode = cfg.Bind<bool>("1. General", "DebugMode", false, "Verbose logging: which weathers were unlocked, weights written, time transitions.");
			WeatherWeights = cfg.Bind<string>("2. Weathers", "Weather weights", "Rainy@120; Foggy@100; Stormy@60; Flooded@40; Eclipsed@50", "Weathers allowed on Gordion and how likely each one is, written as Name@Weight and separated by semicolons. Names are the ones WeatherRegistry uses for its config section titles, so combined and progressing weathers work too: Stormy + Rainy@40; Eclipsed > Foggy@20. Weight 0 removes a weather this mod added earlier. Weights are relative to each other and to 'Clear weather weight'.");
			ClearWeatherWeight = cfg.Bind<int>("2. Weathers", "Clear weather weight", 200, new ConfigDescription("Weight of clear weather (None) on Gordion, i.e. how often the moon stays as it is in vanilla. Set to 0 to guarantee some weather on every visit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000), Array.Empty<object>()));
			RespectExistingConfig = cfg.Bind<bool>("2. Weathers", "Respect existing config", true, "Leave a weather alone if it already has a Gordion weight in mrov.WeatherRegistry.cfg. Keeps hand-tuned entries (for example an Eclipsed you unblocked yourself) from being overwritten by this mod's defaults.");
			TimeMode = cfg.Bind<GordionTimeMode>("3. Time", "Gordion time mode", GordionTimeMode.RealTime, "Off       - no day cycle; weather is fixed for the whole visit (vanilla behaviour).\nRealTime  - start the game's own clock on Gordion while landed, so progressing weather, the rising Flooded water and the HUD clock all work. planetHasTime is deliberately left alone, so the ship still never leaves on its own, no end-of-round stats screen appears, and landing late in the day is not blocked.\nSimulated - never touch the game clock at all; drive weather stages and the HUD clock from this mod's own timer instead. Use it if RealTime upsets another mod.");
			FreezeDeadline = cfg.Bind<bool>("3. Time", "Freeze deadline on Gordion", true, "RealTime only. The vanilla clock drains the quota deadline as it runs, which on Gordion would both cost you days and move the company buying rate — neither happens in vanilla, where the clock is stopped. Leave this on to hold the deadline still for the visit.");
			ShipLeavesAtEndOfDay = cfg.Bind<bool>("3. Time", "Ship leaves at end of day", true, "RealTime only. Let the ship fly off on its own when the Gordion day runs out, exactly as it does on every other moon, with the usual warning at 90% of the day. Vanilla cannot do this at the Company because the whole midnight-departure branch sits behind planetHasTime, so the mod calls the game's own networked departure itself. Turn it off to keep leaving manual and never risk being cut off mid-sale.");
			ShowClock = cfg.Bind<bool>("3. Time", "Show clock on Gordion", true, "Show the HUD clock while on Gordion, indoors included. Vanilla hides the clock whenever you count as inside, which at the Company is most of the visit, so the mod asserts it instead. Works in both RealTime and Simulated.");
			DayLengthSeconds = cfg.Bind<float>("3. Time", "Day length seconds", 1200f, new ConfigDescription("Simulated only: real seconds for a full Gordion day, i.e. how long progressing weather takes to run through all of its stages.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(60f, 7200f), Array.Empty<object>()));
		}

		public Dictionary<string, int> WeatherWeightMap()
		{
			string text = WeatherWeights.Value ?? string.Empty;
			if (_weights != null && _weightsSource == text)
			{
				return _weights;
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			string[] array = text.Split(';');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0)
				{
					continue;
				}
				int num = text2.LastIndexOf('@');
				if (num <= 0)
				{
					Plugin.Log.LogWarning((object)("[Weathers] Ignoring '" + text2 + "': expected the form Name@Weight."));
					continue;
				}
				string text3 = NormalizeName(text2.Substring(0, num));
				string text4 = text2.Substring(num + 1).Trim();
				int result;
				if (text3.Length == 0)
				{
					Plugin.Log.LogWarning((object)("[Weathers] Ignoring '" + text2 + "': the weather name is empty."));
				}
				else if (!int.TryParse(text4, out result) || result < 0)
				{
					Plugin.Log.LogWarning((object)("[Weathers] Ignoring '" + text2 + "': '" + text4 + "' is not a weight of 0 or more."));
				}
				else
				{
					dictionary[text3] = result;
				}
			}
			_weights = dictionary;
			_weightsSource = text;
			return dictionary;
		}

		public static string NormalizeName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(name.Length);
			foreach (char c in name)
			{
				if (c != ' ' && c != '\t' && c != '-' && c != '_')
				{
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal static class ProgressionDriver
	{
		private static List<ProgressionStage> _stages;

		private static int _nextStage;

		private static bool _active;

		public static void Begin()
		{
			_stages = null;
			_nextStage = 0;
			_active = false;
			if (!IsHost())
			{
				return;
			}
			SelectableLevel level = GordionLevel.Level;
			if ((Object)(object)level == (Object)null)
			{
				return;
			}
			try
			{
				Weather currentWeather = WeatherManager.GetCurrentWeather(level);
				if (currentWeather == null)
				{
					return;
				}
				List<ProgressionStage> stages = WeatherTweaksCompat.GetStages(currentWeather);
				if (stages.Count == 0)
				{
					Plugin.DebugLog("'" + currentWeather.Name + "' has no progression stages — the weather stays put for this visit.");
					return;
				}
				_stages = stages;
				_active = true;
				List<string> list = new List<string>(stages.Count);
				foreach (ProgressionStage item in stages)
				{
					list.Add($"{item.Name}@{item.DayTime:0.00}");
				}
				Plugin.Log.LogInfo((object)("Gordion progression for '" + currentWeather.Name + "': " + string.Join(" -> ", list) + "."));
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not set up Gordion weather progression: {arg}");
				_active = false;
			}
		}

		public static void Stop()
		{
			_stages = null;
			_nextStage = 0;
			_active = false;
		}

		public static void Tick(float normalizedTimeOfDay)
		{
			if (!_active || _stages == null)
			{
				return;
			}
			while (_nextStage < _stages.Count && _stages[_nextStage].DayTime <= normalizedTimeOfDay)
			{
				ProgressionStage progressionStage = _stages[_nextStage];
				_nextStage++;
				try
				{
					WeatherController.ChangeCurrentWeather(progressionStage.Weather);
					Plugin.Log.LogInfo((object)$"Gordion weather progressed to '{progressionStage.Name}' at {normalizedTimeOfDay:0.00} of the day.");
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Could not apply progression stage '" + progressionStage.Name + "': " + ex.Message));
				}
			}
			if (_nextStage >= _stages.Count)
			{
				_active = false;
			}
		}

		private static bool IsHost()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				return ((NetworkBehaviour)instance).IsHost;
			}
			return false;
		}
	}
	internal sealed class RealTimeDriver : MonoBehaviour
	{
		private static RealTimeDriver _instance;

		private bool _departureCalled;

		private bool _warningCalled;

		private bool _pushedEndOfDay;

		public static void Begin()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_instance != (Object)null))
			{
				GameObject val = new GameObject("WeatherGordion_RealTimeDriver");
				Object.DontDestroyOnLoad((Object)val);
				((Object)val).hideFlags = (HideFlags)61;
				_instance = val.AddComponent<RealTimeDriver>();
			}
		}

		public static void Stop()
		{
			if (!((Object)(object)_instance == (Object)null))
			{
				ClockOverlay.Hide();
				Object.Destroy((Object)(object)((Component)_instance).gameObject);
				_instance = null;
			}
		}

		private void LateUpdate()
		{
			try
			{
				Tick();
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("RealTime driver tick failed: " + ex.Message);
			}
		}

		private void Tick()
		{
			TimeOfDay instance = TimeOfDay.Instance;
			StartOfRound instance2 = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance2 == (Object)null) && TimeController.ClockRunning && instance.currentDayTimeStarted && !(instance.totalTime <= 0f))
			{
				KeepDayFromFreezing(instance);
				float num = (instance.normalizedTimeOfDay = Mathf.Clamp01(instance.currentDayTime / instance.totalTime));
				ClockOverlay.Draw(num);
				HandleEndOfDay(instance, instance2, num);
			}
		}

		private void KeepDayFromFreezing(TimeOfDay time)
		{
			if (!(time.globalTimeAtEndOfDay > time.globalTime + 0.01f) && !(time.currentDayTime >= time.totalTime))
			{
				SelectableLevel level = GordionLevel.Level;
				float num = (((Object)(object)level != (Object)null) ? Mathf.Max(0.01f, level.DaySpeedMultiplier) : 1f);
				time.globalTimeAtEndOfDay = time.globalTime + (time.totalTime - time.currentDayTime) / num;
				if (!_pushedEndOfDay)
				{
					_pushedEndOfDay = true;
					Plugin.Log.LogWarning((object)("Gordion's end of day had fallen behind the clock and the day would have frozen; pushed it " + $"to {time.globalTimeAtEndOfDay:0.##}."));
				}
			}
		}

		private void HandleEndOfDay(TimeOfDay time, StartOfRound round, float normalized)
		{
			if (!Plugin.Cfg.ShipLeavesAtEndOfDay.Value || round.shipIsLeaving)
			{
				return;
			}
			if (!_warningCalled && normalized > 0.9f)
			{
				_warningCalled = true;
				try
				{
					HUDManager instance = HUDManager.Instance;
					if ((Object)(object)instance != (Object)null)
					{
						instance.ReadDialogue(time.shipLeavingSoonDialogue);
						((Behaviour)instance.shipLeavingEarlyIcon).enabled = true;
					}
					time.shipLeavingAlertCalled = true;
				}
				catch (Exception ex)
				{
					Plugin.DebugLog("Ship-leaving warning failed: " + ex.Message);
				}
			}
			if (!_departureCalled && ((NetworkBehaviour)round).IsServer && !(normalized < time.shipLeaveAutomaticallyTime))
			{
				_departureCalled = true;
				time.SetShipToLeaveOnMidnightClientRpc();
				Plugin.Log.LogInfo((object)"Gordion reached the end of the day — the ship is leaving on its own.");
			}
		}
	}
	internal sealed class SimulatedClock : MonoBehaviour
	{
		private static SimulatedClock _instance;

		private float _elapsed;

		private float _dayLength;

		public static float Normalized
		{
			get
			{
				if (!((Object)(object)_instance != (Object)null))
				{
					return 0f;
				}
				return _instance.Current;
			}
		}

		public static bool Running => (Object)(object)_instance != (Object)null;

		private float Current
		{
			get
			{
				if (!(_dayLength <= 0f))
				{
					return Mathf.Clamp01(_elapsed / _dayLength);
				}
				return 0f;
			}
		}

		public static void Begin()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_instance != (Object)null))
			{
				GameObject val = new GameObject("WeatherGordion_SimulatedClock");
				Object.DontDestroyOnLoad((Object)val);
				((Object)val).hideFlags = (HideFlags)61;
				_instance = val.AddComponent<SimulatedClock>();
				_instance._dayLength = Mathf.Max(1f, Plugin.Cfg.DayLengthSeconds.Value);
				ProgressionDriver.Begin();
				Plugin.Log.LogInfo((object)$"Simulated Gordion day started ({_instance._dayLength:0} s). The game clock is untouched.");
			}
		}

		public static void Stop()
		{
			if (!((Object)(object)_instance == (Object)null))
			{
				ProgressionDriver.Stop();
				ClockOverlay.Hide();
				Object.Destroy((Object)(object)((Component)_instance).gameObject);
				_instance = null;
				Plugin.DebugLog("Simulated Gordion day stopped.");
			}
		}

		private void Update()
		{
			try
			{
				Tick();
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Simulated clock tick failed: " + ex.Message);
			}
		}

		private void Tick()
		{
			if (_elapsed < _dayLength)
			{
				_elapsed += Time.deltaTime;
			}
			float current = Current;
			TimeOfDay instance = TimeOfDay.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				instance.normalizedTimeOfDay = current;
				instance.currentDayTime = current * instance.totalTime;
				ClockOverlay.Draw(current);
			}
			ProgressionDriver.Tick(current);
		}
	}
	internal sealed class StormyMetal : MonoBehaviour
	{
		private const float RescanInterval = 6f;

		private static StormyMetal _instance;

		private static FieldInfo _metalObjectsField;

		private static bool _fieldMissingLogged;

		private float _nextScan;

		private int _lastCount = -1;

		public static void Begin()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_instance != (Object)null))
			{
				GameObject val = new GameObject("WeatherGordion_StormyMetal");
				Object.DontDestroyOnLoad((Object)val);
				((Object)val).hideFlags = (HideFlags)61;
				_instance = val.AddComponent<StormyMetal>();
			}
		}

		public static void Stop()
		{
			if (!((Object)(object)_instance == (Object)null))
			{
				Object.Destroy((Object)(object)((Component)_instance).gameObject);
				_instance = null;
			}
		}

		private void Update()
		{
			if (Time.unscaledTime < _nextScan)
			{
				return;
			}
			_nextScan = Time.unscaledTime + 6f;
			try
			{
				Rescan();
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Storm metal rescan failed: " + ex.Message);
			}
		}

		private void Rescan()
		{
			if (!GordionLevel.IsCurrent())
			{
				return;
			}
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || !((NetworkBehaviour)instance).IsServer)
			{
				return;
			}
			StormyWeather val = Object.FindObjectOfType<StormyWeather>();
			if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
			{
				return;
			}
			if ((object)_metalObjectsField == null)
			{
				_metalObjectsField = AccessTools.Field(typeof(StormyWeather), "metalObjects");
			}
			if (_metalObjectsField == null)
			{
				if (!_fieldMissingLogged)
				{
					_fieldMissingLogged = true;
					Plugin.Log.LogWarning((object)"StormyWeather.metalObjects was not found, so lightning targets cannot be refreshed on Gordion. Storms still work; they just keep whatever targets they found at first.");
				}
			}
			else
			{
				if (!(_metalObjectsField.GetValue(val) is List<GrabbableObject> list))
				{
					return;
				}
				list.Clear();
				GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
				foreach (GrabbableObject val2 in array)
				{
					if ((Object)(object)val2 != (Object)null && (Object)(object)val2.itemProperties != (Object)null && val2.itemProperties.isConductiveMetal)
					{
						list.Add(val2);
					}
				}
				if (list.Count != _lastCount)
				{
					_lastCount = list.Count;
					Plugin.DebugLog($"Storm lightning targets on Gordion: {list.Count} conductive item(s).");
				}
			}
		}
	}
	internal static class TimeController
	{
		private static bool _clockStarted;

		private static float _deadlineSnapshot;

		private static bool _hasDeadlineSnapshot;

		private static SelectableLevel _speedPatchedLevel;

		private static float _originalDaySpeed;

		private static SelectableLevel _offsetPatchedLevel;

		private static float _originalOffset;

		public static bool ClockRunning => _clockStarted;

		public static bool TryGetFrozenDeadline(out float value)
		{
			value = _deadlineSnapshot;
			if (_clockStarted && _hasDeadlineSnapshot)
			{
				return Plugin.Cfg.FreezeDeadline.Value;
			}
			return false;
		}

		public static void OnLandedOnGordion()
		{
			if (Plugin.Cfg != null && Plugin.Cfg.Enabled.Value)
			{
				switch (Plugin.Cfg.TimeMode.Value)
				{
				case GordionTimeMode.RealTime:
					StartVanillaClock();
					StormyMetal.Begin();
					break;
				case GordionTimeMode.Simulated:
					SimulatedClock.Begin();
					StormyMetal.Begin();
					break;
				case GordionTimeMode.Off:
					break;
				}
			}
		}

		public static void OnLeftGordion()
		{
			SimulatedClock.Stop();
			RestoreImmediately();
		}

		public static void RestoreImmediately()
		{
			RealTimeDriver.Stop();
			StormyMetal.Stop();
			RestoreDeadline();
			RestoreDaySpeed();
			if (_clockStarted)
			{
				TimeOfDay instance = TimeOfDay.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.currentDayTimeStarted = false;
					instance.movingGlobalTimeForward = false;
				}
				_clockStarted = false;
				Plugin.DebugLog("Gordion clock stopped.");
			}
			_hasDeadlineSnapshot = false;
		}

		private static void StartVanillaClock()
		{
			TimeOfDay instance = TimeOfDay.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Landed on Gordion but TimeOfDay is missing — the clock stays stopped.");
				return;
			}
			if (_clockStarted || instance.currentDayTimeStarted)
			{
				SnapshotDeadline(instance);
				_clockStarted = true;
				RealTimeDriver.Begin();
				return;
			}
			EnsureDaySpeed();
			ZeroDayOffset(instance);
			SnapshotDeadline(instance);
			instance.currentDayTimeStarted = true;
			instance.movingGlobalTimeForward = true;
			_clockStarted = true;
			RealTimeDriver.Begin();
			SelectableLevel level = GordionLevel.Level;
			Plugin.Log.LogInfo((object)($"Gordion clock started (globalTime {instance.globalTime:0.##}, totalTime {instance.totalTime:0.##}, " + $"daySpeed {level?.DaySpeedMultiplier:0.###}, offset {level?.OffsetFromGlobalTime:0.##}, " + $"deadline held: {Plugin.Cfg.FreezeDeadline.Value})."));
		}

		private static void ZeroDayOffset(TimeOfDay time)
		{
			SelectableLevel level = GordionLevel.Level;
			if (!((Object)(object)level == (Object)null))
			{
				_offsetPatchedLevel = level;
				_originalOffset = level.OffsetFromGlobalTime;
				level.OffsetFromGlobalTime = 0f;
				Plugin.DebugLog($"Gordion OffsetFromGlobalTime {_originalOffset:0.##} -> 0 so the day can run " + $"(globalTime {time.globalTime:0.##} is server-synced, so every player gets the same time).");
			}
		}

		private static void EnsureDaySpeed()
		{
			SelectableLevel level = GordionLevel.Level;
			if (!((Object)(object)level == (Object)null))
			{
				Plugin.DebugLog($"Gordion DaySpeedMultiplier = {level.DaySpeedMultiplier}, " + $"OffsetFromGlobalTime = {level.OffsetFromGlobalTime}.");
				if (!(level.DaySpeedMultiplier > 0f))
				{
					_speedPatchedLevel = level;
					_originalDaySpeed = level.DaySpeedMultiplier;
					level.DaySpeedMultiplier = 1f;
					Plugin.Log.LogInfo((object)($"Gordion had DaySpeedMultiplier = {_originalDaySpeed}, which would freeze the day and " + "divide by zero at the start of it; using 1 for this visit."));
				}
			}
		}

		private static void RestoreDaySpeed()
		{
			if ((Object)(object)_speedPatchedLevel != (Object)null)
			{
				_speedPatchedLevel.DaySpeedMultiplier = _originalDaySpeed;
				_speedPatchedLevel = null;
			}
			if ((Object)(object)_offsetPatchedLevel != (Object)null)
			{
				_offsetPatchedLevel.OffsetFromGlobalTime = _originalOffset;
				_offsetPatchedLevel = null;
			}
		}

		private static void SnapshotDeadline(TimeOfDay time)
		{
			if (!_hasDeadlineSnapshot)
			{
				_deadlineSnapshot = time.timeUntilDeadline;
				_hasDeadlineSnapshot = true;
				Plugin.DebugLog($"Deadline snapshot: timeUntilDeadline = {_deadlineSnapshot:0.##}.");
			}
		}

		private static void RestoreDeadline()
		{
			if (!_hasDeadlineSnapshot || !_clockStarted)
			{
				return;
			}
			TimeOfDay instance = TimeOfDay.Instance;
			if ((Object)(object)instance == (Object)null || !Plugin.Cfg.FreezeDeadline.Value)
			{
				return;
			}
			try
			{
				instance.timeUntilDeadline = _deadlineSnapshot;
				instance.UpdateProfitQuotaCurrentTime();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not restore the deadline after a Gordion visit: " + ex.Message));
			}
		}
	}
	internal static class WeatherUnlocker
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Event <0>__OnSetupFinished;

			public static ParameterEvent<int> <1>__OnDayChanged;

			public static Func<SelectableLevel, string> <2>__ConfigKey;
		}

		private static readonly HashSet<LevelWeatherType> Added = new HashSet<LevelWeatherType>();

		private static readonly HashSet<string> PreExistingWeights = new HashSet<string>(StringComparer.Ordinal);

		private static bool _snapshotTaken;

		private static bool _subscribed;

		private static bool _loggedSummary;

		public static void Subscribe()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			if (_subscribed)
			{
				return;
			}
			try
			{
				WeatherRegistryEvent setupFinished = EventManager.SetupFinished;
				object obj = <>O.<0>__OnSetupFinished;
				if (obj == null)
				{
					Event val = OnSetupFinished;
					<>O.<0>__OnSetupFinished = val;
					obj = (object)val;
				}
				((CustomEvent)setupFinished).AddListener((Event)obj);
				((CustomEvent<int>)(object)EventManager.DayChanged).AddListener((ParameterEvent<int>)OnDayChanged);
				_subscribed = true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not subscribe to WeatherRegistry events: " + ex.Message + ". Gordion weather will still be applied from the SetPlanetsWeather patch."));
			}
		}

		public static void Unsubscribe()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			if (!_subscribed)
			{
				return;
			}
			try
			{
				WeatherRegistryEvent setupFinished = EventManager.SetupFinished;
				object obj = <>O.<0>__OnSetupFinished;
				if (obj == null)
				{
					Event val = OnSetupFinished;
					<>O.<0>__OnSetupFinished = val;
					obj = (object)val;
				}
				((CustomEvent)setupFinished).RemoveListener((Event)obj);
				((CustomEvent<int>)(object)EventManager.DayChanged).RemoveListener((ParameterEvent<int>)OnDayChanged);
			}
			catch
			{
			}
			_subscribed = false;
		}

		private static void OnSetupFinished()
		{
			Apply("WeatherRegistry setup finished");
		}

		private static void OnDayChanged(int day)
		{
			Apply($"day {day} started");
		}

		public static void Reset()
		{
			Added.Clear();
			WeatherVariables.Reset();
			_loggedSummary = false;
		}

		public static void Apply(string reason)
		{
			if (Plugin.Cfg == null || !Plugin.Cfg.Enabled.Value)
			{
				return;
			}
			SelectableLevel level = GordionLevel.Level;
			if ((Object)(object)level == (Object)null)
			{
				return;
			}
			try
			{
				ApplyCore(level, reason);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to unlock weather on Gordion ({reason}): {arg}");
			}
		}

		private static void ApplyCore(SelectableLevel gordion, string reason)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			List<Weather> weathers = WeatherManager.Weathers;
			if (weathers == null || weathers.Count == 0)
			{
				Plugin.DebugLog("No weathers registered yet (" + reason + "); nothing to unlock.");
				return;
			}
			TakeSnapshot(gordion, weathers);
			Dictionary<string, int> dictionary = Plugin.Cfg.WeatherWeightMap();
			List<string> list = new List<string>();
			List<string> list2 = new List<string>(dictionary.Keys);
			foreach (Weather item in weathers)
			{
				if (item == null)
				{
					continue;
				}
				string text = MatchKey(item, dictionary);
				if (text == null)
				{
					if ((int)item.Type == 0)
					{
						SetLevelWeight(item, gordion, Plugin.Cfg.ClearWeatherWeight.Value);
					}
					continue;
				}
				list2.Remove(text);
				int num = dictionary[text];
				if (num == 0)
				{
					RemoveFromPool(gordion, item);
				}
				else if (Plugin.Cfg.RespectExistingConfig.Value && HasHandTunedWeight(item))
				{
					Plugin.DebugLog("'" + item.Name + "' already has a Gordion weight in mrov.WeatherRegistry.cfg — left alone.");
					AddToPool(gordion, item);
					list.Add(item.Name + " (kept existing weight)");
				}
				else
				{
					AllowOnLevel(item, gordion);
					SetLevelWeight(item, gordion, num);
					AddToPool(gordion, item);
					list.Add($"{item.Name}@{num}");
				}
			}
			if (!_loggedSummary || Plugin.Cfg.DebugMode.Value)
			{
				_loggedSummary = true;
				Plugin.Log.LogInfo((object)("Gordion weather pool (" + reason + "): " + ((list.Count > 0) ? string.Join(", ", list) : "nothing") + $"; clear weight {Plugin.Cfg.ClearWeatherWeight.Value}."));
				if (list2.Count > 0)
				{
					Plugin.Log.LogWarning((object)("These configured weathers are not registered and were skipped: " + string.Join(", ", list2) + ". Check the section titles in mrov.WeatherRegistry.cfg for the exact names — combined weathers only exist while WeatherTweaks or Combined Weathers Toolkit is installed."));
				}
			}
		}

		private static string MatchKey(Weather weather, Dictionary<string, int> wanted)
		{
			string text = PluginConfig.NormalizeName(weather.Name);
			if (wanted.ContainsKey(text))
			{
				return text;
			}
			try
			{
				string text2 = PluginConfig.NormalizeName(weather.GetAlphanumericName());
				if (text2.Length > 0 && wanted.ContainsKey(text2))
				{
					return text2;
				}
			}
			catch
			{
			}
			return null;
		}

		private static void AllowOnLevel(Weather weather, SelectableLevel level)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			LevelListConfigHandler val = weather.Config?.LevelFilters;
			if (val == null)
			{
				return;
			}
			bool flag = (int)weather.LevelFilteringOption == 0;
			SelectableLevel[] array = ((ConfigHandler<SelectableLevel[], string>)(object)val).Value ?? Array.Empty<SelectableLevel>();
			if (flag && array.Length == 0)
			{
				return;
			}
			bool flag2 = array.Contains(level);
			if (flag != flag2)
			{
				string text = SerialiseLevels(flag ? array.Concat((IEnumerable<SelectableLevel>)(object)new SelectableLevel[1] { level }) : array.Where((SelectableLevel l) => (Object)(object)l != (Object)(object)level));
				if (WriteHandler<SelectableLevel[]>((ConfigHandler<SelectableLevel[], string>)(object)val, text))
				{
					Plugin.DebugLog("'" + weather.Name + "': " + (flag ? "added Gordion to" : "removed Gordion from") + " its level filter -> '" + text + "'.");
				}
			}
		}

		private static void TakeSnapshot(SelectableLevel gordion, List<Weather> weathers)
		{
			if (_snapshotTaken)
			{
				return;
			}
			_snapshotTaken = true;
			foreach (Weather weather in weathers)
			{
				if (weather != null && CarriesWeightFor(weather, gordion))
				{
					PreExistingWeights.Add(weather.Name ?? string.Empty);
				}
			}
			if (PreExistingWeights.Count > 0)
			{
				Plugin.DebugLog("Already had a Gordion weight in mrov.WeatherRegistry.cfg: " + string.Join(", ", PreExistingWeights) + ".");
			}
		}

		private static bool HasHandTunedWeight(Weather weather)
		{
			return PreExistingWeights.Contains(weather.Name ?? string.Empty);
		}

		private static bool CarriesWeightFor(Weather weather, SelectableLevel level)
		{
			LevelRarity[] array = ((ConfigHandler<LevelRarity[], string>)(object)weather.Config?.LevelWeights)?.Value;
			if (array == null)
			{
				return false;
			}
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] != null && (Object)(object)array[i].Level == (Object)(object)level)
				{
					return true;
				}
			}
			return false;
		}

		private static void SetLevelWeight(Weather weather, SelectableLevel level, int weight)
		{
			LevelWeightsConfigHandler val = weather.Config?.LevelWeights;
			if (val == null || (Plugin.Cfg.RespectExistingConfig.Value && HasHandTunedWeight(weather)))
			{
				return;
			}
			LevelRarity[] obj = ((ConfigHandler<LevelRarity[], string>)(object)val).Value ?? Array.Empty<LevelRarity>();
			string arg = GordionLevel.ConfigKey(level);
			List<string> list = new List<string>();
			bool flag = false;
			LevelRarity[] array = obj;
			foreach (LevelRarity val2 in array)
			{
				if ((Object)(object)((val2 != null) ? val2.Level : null) == (Object)null)
				{
					continue;
				}
				if ((Object)(object)val2.Level == (Object)(object)level)
				{
					if (!flag)
					{
						list.Add($"{arg}@{weight}");
						flag = true;
					}
				}
				else
				{
					list.Add($"{GordionLevel.ConfigKey(val2.Level)}@{((Rarity)val2).Weight}");
				}
			}
			if (!flag)
			{
				list.Add($"{arg}@{weight}");
			}
			string text = string.Join(";", list) + ";";
			if (WriteHandler<LevelRarity[]>((ConfigHandler<LevelRarity[], string>)(object)val, text))
			{
				Plugin.DebugLog("'" + weather.Name + "': level weights -> '" + text + "'.");
			}
		}

		private static void AddToPool(SelectableLevel level, Weather weather)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			RandomWeatherWithVariables val = FindInPool(level, weather.VanillaWeatherType);
			if (val != null)
			{
				if (Added.Contains(weather.VanillaWeatherType) && WeatherVariables.IsUnset(val))
				{
					WeatherVariables.Apply(val, weather, level);
				}
				return;
			}
			RandomWeatherWithVariables val2 = new RandomWeatherWithVariables
			{
				weatherType = weather.VanillaWeatherType
			};
			WeatherVariables.Apply(val2, weather, level);
			WeatherController.AddRandomWeather(level, val2);
			Added.Add(val2.weatherType);
			Plugin.DebugLog("'" + weather.Name + "' added to Gordion's weather pool " + $"(variables {val2.weatherVariable}/{val2.weatherVariable2}).");
		}

		private static void RemoveFromPool(SelectableLevel level, Weather weather)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			LevelWeatherType vanillaWeatherType = weather.VanillaWeatherType;
			if (Added.Contains(vanillaWeatherType) && IsInPool(level, vanillaWeatherType))
			{
				WeatherController.RemoveRandomWeather(level, vanillaWeatherType);
				Added.Remove(vanillaWeatherType);
				Plugin.DebugLog("'" + weather.Name + "' removed from Gordion's weather pool (configured weight 0).");
			}
		}

		private static bool IsInPool(SelectableLevel level, LevelWeatherType type)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return FindInPool(level, type) != null;
		}

		private static RandomWeatherWithVariables FindInPool(SelectableLevel level, LevelWeatherType type)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			RandomWeatherWithVariables[] randomWeathers = level.randomWeathers;
			if (randomWeathers == null)
			{
				return null;
			}
			for (int i = 0; i < randomWeathers.Length; i++)
			{
				if (randomWeathers[i] != null && randomWeathers[i].weatherType == type)
				{
					return randomWeathers[i];
				}
			}
			return null;
		}

		private static bool WriteHandler<TValue>(ConfigHandler<TValue, string> handler, string raw)
		{
			try
			{
				if (!handler.ConfigEntryActive)
				{
					if (((ConfigHandler<TValue, string>)(object)handler).DefaultValue == raw)
					{
						return false;
					}
					((ConfigHandler<TValue, string>)(object)handler).DefaultValue = raw;
					return true;
				}
				ConfigEntry<string> configEntry = ((ConfigHandler<TValue, string>)(object)handler).ConfigEntry;
				if (configEntry.Value == raw)
				{
					return false;
				}
				ConfigFile configFile = ((ConfigEntryBase)configEntry).ConfigFile;
				bool saveOnConfigSet = configFile != null && configFile.SaveOnConfigSet;
				if (configFile != null)
				{
					configFile.SaveOnConfigSet = false;
				}
				try
				{
					configEntry.Value = raw;
				}
				finally
				{
					if (configFile != null)
					{
						configFile.SaveOnConfigSet = saveOnConfigSet;
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not write a WeatherRegistry config handler: " + ex.Message));
				return false;
			}
		}

		private static string SerialiseLevels(IEnumerable<SelectableLevel> levels)
		{
			List<string> list = (from n in levels.Where((SelectableLevel l) => (Object)(object)l != (Object)null).Select(GordionLevel.ConfigKey)
				where n.Length > 0
				select n).Distinct().ToList();
			if (list.Count != 0)
			{
				return string.Join(";", list) + ";";
			}
			return string.Empty;
		}
	}
	internal static class WeatherVariables
	{
		private struct Variables
		{
			public int Variable1;

			public int Variable2;

			public Color Color;

			public string Source;
		}

		private static readonly Dictionary<LevelWeatherType, Variables> Cache = new Dictionary<LevelWeatherType, Variables>();

		public static void Reset()
		{
			Cache.Clear();
		}

		public static void Apply(RandomWeatherWithVariables entry, Weather weather, SelectableLevel exclude)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (entry != null)
			{
				if (TryFindDonor(entry.weatherType, exclude, out var donor))
				{
					entry.weatherVariable = donor.Variable1;
					entry.weatherVariable2 = donor.Variable2;
					entry.weatherVariableColor = donor.Color;
					Plugin.DebugLog($"'{((weather != null) ? weather.Name : null)}' variables {donor.Variable1}/{donor.Variable2} borrowed from {donor.Source}.");
				}
				else
				{
					entry.weatherVariable = (((Object)(object)weather?.Effect != (Object)null) ? weather.Effect.DefaultVariable1 : 0);
					entry.weatherVariable2 = (((Object)(object)weather?.Effect != (Object)null) ? weather.Effect.DefaultVariable2 : 0);
					Plugin.DebugLog("'" + ((weather != null) ? weather.Name : null) + "': no moon defines this weather, using the effect's own defaults " + $"{entry.weatherVariable}/{entry.weatherVariable2}.");
				}
			}
		}

		public static bool IsUnset(RandomWeatherWithVariables entry)
		{
			if (entry != null && entry.weatherVariable == 0)
			{
				return entry.weatherVariable2 == 0;
			}
			return false;
		}

		private static bool TryFindDonor(LevelWeatherType type, SelectableLevel exclude, out Variables donor)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (Cache.TryGetValue(type, out donor))
			{
				return donor.Source != null;
			}
			donor = default(Variables);
			SelectableLevel[] array = StartOfRound.Instance?.levels;
			if (array == null)
			{
				return false;
			}
			if (TryScan(array, type, exclude, vanillaOnly: true, out donor) || TryScan(array, type, exclude, vanillaOnly: false, out donor))
			{
				Cache[type] = donor;
				return true;
			}
			Cache[type] = default(Variables);
			return false;
		}

		private static bool TryScan(SelectableLevel[] levels, LevelWeatherType type, SelectableLevel exclude, bool vanillaOnly, out Variables donor)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			donor = default(Variables);
			foreach (SelectableLevel val in levels)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)exclude || val.randomWeathers == null || (vanillaOnly && !IsVanilla(val)))
				{
					continue;
				}
				RandomWeatherWithVariables[] randomWeathers = val.randomWeathers;
				foreach (RandomWeatherWithVariables val2 in randomWeathers)
				{
					if (val2 != null && val2.weatherType == type && (val2.weatherVariable != 0 || val2.weatherVariable2 != 0))
					{
						donor = new Variables
						{
							Variable1 = val2.weatherVariable,
							Variable2 = val2.weatherVariable2,
							Color = val2.weatherVariableColor,
							Source = (val.PlanetName ?? ((Object)val).name)
						};
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsVanilla(SelectableLevel level)
		{
			try
			{
				return LevelHelper.IsVanillaLevel(level);
			}
			catch
			{
				return false;
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Timofey.WeatherGordion";

		public const string PLUGIN_NAME = "WeatherGordion";

		public const string PLUGIN_VERSION = "1.0.5";
	}
}
namespace WeatherGordion.Patches
{
	[HarmonyPatch]
	internal static class RoundManagerPatches
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(RoundManager), "SetToCurrentLevelWeather")]
		private static void SetToCurrentLevelWeather_Prefix()
		{
			try
			{
				WeatherUnlocker.Apply("the level is applying its weather");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not prepare Gordion's weather variables: {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal static class SetPlanetsWeatherPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(StartOfRound), "SetPlanetsWeather")]
		private static void SetPlanetsWeather_Prefix(StartOfRound __instance)
		{
			try
			{
				GordionLevel.Resolve(__instance);
				WeatherUnlocker.Apply("weather is being selected");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Could not prepare Gordion before weather selection: {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal static class StartOfRoundPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		private static void Awake_Postfix(StartOfRound __instance)
		{
			try
			{
				GordionLevel.Reset();
				WeatherUnlocker.Reset();
				GordionLevel.Resolve(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"StartOfRound.Awake handler failed: {arg}");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
		private static void ShipLeave_Prefix()
		{
			try
			{
				TimeController.OnLeftGordion();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"ShipLeave handler failed: {arg}");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(StartOfRound), "PassTimeToNextDay")]
		private static void PassTimeToNextDay_Prefix()
		{
			try
			{
				TimeController.RestoreImmediately();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"PassTimeToNextDay handler failed: {arg}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "OnDestroy")]
		private static void OnDestroy_Postfix()
		{
			try
			{
				TimeController.RestoreImmediately();
				SimulatedClock.Stop();
				GordionLevel.Reset();
				WeatherUnlocker.Reset();
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	internal static class TimeOfDayPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(TimeOfDay), "MoveGlobalTime")]
		private static void MoveGlobalTime_Postfix(TimeOfDay __instance)
		{
			try
			{
				if (TimeController.TryGetFrozenDeadline(out var value))
				{
					__instance.timeUntilDeadline = value;
				}
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Deadline hold failed: " + ex.Message);
			}
		}
	}
}
namespace WeatherGordion.Compat
{
	internal sealed class ProgressionStage
	{
		public float DayTime;

		public Weather Weather;

		public string Name;
	}
	internal static class WeatherTweaksCompat
	{
		private static bool _probed;

		private static bool _available;

		private static MethodInfo _getFullWeatherType;

		private static Type _progressingType;

		private static FieldInfo _weatherEntries;

		private static FieldInfo _entryDayTime;

		private static MethodInfo _entryGetWeather;

		public static bool Available
		{
			get
			{
				Probe();
				return _available;
			}
		}

		public static List<ProgressionStage> GetStages(Weather weather)
		{
			List<ProgressionStage> list = new List<ProgressionStage>();
			if (weather == null || !Available)
			{
				return list;
			}
			try
			{
				object obj = _getFullWeatherType.Invoke(null, new object[1] { weather });
				if (obj == null || !_progressingType.IsInstanceOfType(obj))
				{
					return list;
				}
				if (!(_weatherEntries.GetValue(obj) is IEnumerable enumerable))
				{
					return list;
				}
				foreach (object item in enumerable)
				{
					if (item != null)
					{
						float dayTime = (float)_entryDayTime.GetValue(item);
						object? obj2 = _entryGetWeather.Invoke(item, null);
						Weather val = (Weather)((obj2 is Weather) ? obj2 : null);
						if (val != null)
						{
							list.Add(new ProgressionStage
							{
								DayTime = dayTime,
								Weather = val,
								Name = val.Name
							});
						}
					}
				}
				list.Sort((ProgressionStage a, ProgressionStage b) => a.DayTime.CompareTo(b.DayTime));
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Could not read progression stages for '" + weather.Name + "': " + ex.Message);
				list.Clear();
			}
			return list;
		}

		private static void Probe()
		{
			if (_probed)
			{
				return;
			}
			_probed = true;
			try
			{
				Type type = FindType("WeatherTweaks.Variables");
				_progressingType = FindType("WeatherTweaks.Definitions.ProgressingWeatherType");
				Type type2 = FindType("WeatherTweaks.Definitions.ProgressingWeatherEntry");
				if (type == null || _progressingType == null || type2 == null)
				{
					Plugin.DebugLog("WeatherTweaks not found — progressing weather stages are unavailable.");
					return;
				}
				_getFullWeatherType = type.GetMethod("GetFullWeatherType", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Weather) }, null);
				_weatherEntries = _progressingType.GetField("WeatherEntries", BindingFlags.Instance | BindingFlags.Public);
				_entryDayTime = type2.GetField("DayTime", BindingFlags.Instance | BindingFlags.Public);
				_entryGetWeather = type2.GetMethod("GetWeather", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
				_available = _getFullWeatherType != null && _weatherEntries != null && _entryDayTime != null && _entryGetWeather != null;
				if (_available)
				{
					Plugin.DebugLog("WeatherTweaks progressing-weather support is available.");
				}
				else
				{
					Plugin.Log.LogWarning((object)"WeatherTweaks is installed but its progressing-weather API did not match what this mod expects; stages will not be stepped through in Simulated mode.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("WeatherTweaks compatibility probe failed: " + ex.Message));
				_available = false;
			}
		}

		private static Type FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(fullName, throwOnError: false);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}
	}
}