Decompiled source of 27 Trudge v1.0.0

BepInEx/plugins/27Trudge/27Trudge.dll

Decompiled 5 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 HarmonyLib;
using LethalLevelLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("27Trudge")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("27Trudge")]
[assembly: AssemblyTitle("27Trudge")]
[assembly: AssemblyVersion("1.0.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 Trudge27
{
	internal static class GrassRuntime
	{
		private static readonly string[] OurScenes = new string[2] { "Level27Trudge", "ReMarchScene" };

		internal const string ExclusionPrefix = "GrassExclusion";

		internal const string ZonePrefix = "GrassZone";

		private const string GrassShaderName = "Shader Graphs/WavingGrass";

		private static readonly string[] AuthoredKeywords = new string[3] { "_ALPHATEST_ON", "_DISABLE_SSR", "_DISABLE_SSR_TRANSPARENT" };

		internal static ConfigEntry<bool> Enabled;

		private static FieldInfo batchesField;

		private static List<Collider> exclusionZones;

		private static List<Collider> inclusionZones;

		private static int zonesForSceneCount = -1;

		private static bool loggedNoRealShader;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("Grass", "Enabled", true, "Spawns grass on Trudge's terrain mesh (or reMarch if enabled).");
			SceneManager.sceneLoaded += delegate
			{
				exclusionZones = null;
				inclusionZones = null;
				zonesForSceneCount = -1;
			};
		}

		private static bool Ours(Component component)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			Scene scene = component.gameObject.scene;
			return ((Scene)(ref scene)).IsValid() && OurScenes.Any((string s) => string.Equals(s, ((Scene)(ref scene)).name, StringComparison.Ordinal));
		}

		internal static void BeforeStart(SpawnGrassOnMesh grass)
		{
			if (Ours((Component)(object)grass) && !Enabled.Value)
			{
				((Behaviour)grass).enabled = false;
				grass.numberOfBlades = 0;
				Plugin.Log.LogInfo((object)("Grass disabled by config; '" + ((Object)((Component)grass).gameObject).name + "' left inert."));
			}
		}

		internal static void AfterStart(SpawnGrassOnMesh grass)
		{
			if (Ours((Component)(object)grass) && Enabled.Value)
			{
				FixShader(grass.material);
				FilterZones(grass);
			}
		}

		private static void FixShader(Material material)
		{
			if ((Object)(object)material == (Object)null)
			{
				return;
			}
			List<Shader> list = (from s in Resources.FindObjectsOfTypeAll<Shader>()
				where (Object)(object)s != (Object)null && string.Equals(((Object)s).name, "Shader Graphs/WavingGrass", StringComparison.Ordinal)
				select s).ToList();
			Shader shader = material.shader;
			int renderQueue = material.renderQueue;
			string[] second = material.enabledKeywords.Select((LocalKeyword k) => ((LocalKeyword)(ref k)).name).ToArray();
			Shader val = shader;
			int passCount = material.passCount;
			foreach (Shader item in list)
			{
				if (!((Object)(object)item == (Object)(object)shader))
				{
					material.shader = item;
					if (material.passCount > passCount)
					{
						passCount = material.passCount;
						val = item;
					}
				}
			}
			material.shader = val;
			if ((Object)(object)val == (Object)(object)shader)
			{
				if (list.Count <= 1 && !loggedNoRealShader)
				{
					loggedNoRealShader = true;
					Plugin.Log.LogWarning((object)(string.Format("Only one loaded shader is named '{0}' ({1} pass(es)), so the ", "Shader Graphs/WavingGrass", passCount) + "game's real graph is not available and '" + ((Object)material).name + "' cannot be made to draw. It ships with the game and is loaded by Vow and Adamance, so visiting either once in a session should make it available."));
				}
				return;
			}
			Shader val2 = val;
			material.renderQueue = renderQueue;
			foreach (string item2 in AuthoredKeywords.Concat(second).Distinct())
			{
				material.EnableKeyword(item2);
			}
			string[] array = ((IEnumerable<string>)AuthoredKeywords).Where((Func<string, bool>)material.IsKeywordEnabled).ToArray();
			string[] array2 = AuthoredKeywords.Where((string k) => !material.IsKeywordEnabled(k)).ToArray();
			Plugin.Log.LogInfo((object)("Rebound '" + ((Object)material).name + "' from the bundle's dummy to the game's '" + ((Object)val2).name + "' " + $"({passCount} passes, beating the dummy's {list.Count} candidate(s) - the dummy has " + $"one). Render queue {renderQueue}. Keywords enabled: " + ((array.Length == 0) ? "NONE" : string.Join(", ", array)) + ((array2.Length == 0) ? "" : ("; would not take: " + string.Join(", ", array2))) + "."));
			if (!material.IsKeywordEnabled("_ALPHATEST_ON"))
			{
				Plugin.Log.LogWarning((object)"'_ALPHATEST_ON' did not take on the grass material, so HDRP will use the variant with no alpha clip and every blade will draw as a solid rectangle of the texture atlas. The real shader was found, so this means it does not declare that keyword - check whether the game's grass shader has changed.");
			}
		}

		private static void FilterZones(SpawnGrassOnMesh grass)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			List<Collider> list = Zones(grass, "GrassZone", ref inclusionZones);
			List<Collider> list2 = Zones(grass, "GrassExclusion", ref exclusionZones).ToList();
			List<Collider> list3 = WaterVolumes(((Component)grass).gameObject.scene);
			if (list3.Count > 0)
			{
				list2.AddRange(list3);
			}
			if (list.Count == 0 && list2.Count == 0)
			{
				return;
			}
			if ((object)batchesField == null)
			{
				batchesField = typeof(SpawnGrassOnMesh).GetField("Batches", BindingFlags.Instance | BindingFlags.NonPublic);
			}
			if (batchesField == null)
			{
				Plugin.Log.LogWarning((object)"SpawnGrassOnMesh has no private 'Batches' field any more, so grass zones cannot be applied. Grass will cover the whole terrain.");
			}
			else
			{
				if (!(batchesField.GetValue(grass) is List<List<Matrix4x4>> list4))
				{
					return;
				}
				int num = 0;
				int num2 = 0;
				int num3 = 0;
				foreach (List<Matrix4x4> item in list4)
				{
					for (int num4 = item.Count - 1; num4 >= 0; num4--)
					{
						Matrix4x4 val = item[num4];
						Vector3 position = ((Matrix4x4)(ref val)).GetPosition();
						if (list.Count > 0 && !Inside(list, position))
						{
							item.RemoveAt(num4);
							num++;
						}
						else if (list2.Count > 0 && Inside(list2, position))
						{
							item.RemoveAt(num4);
							num2++;
						}
					}
					num3 += item.Count;
				}
				Plugin.Log.LogInfo((object)($"Grass on '{((Object)((Component)grass).gameObject).name}': {num3} blade(s) kept" + ((list.Count > 0) ? $", {num} dropped outside {list.Count} zone(s)" : "") + ((list2.Count > 0) ? ($", {num2} dropped inside {list2.Count} exclusion(s)" + ((list3.Count > 0) ? $" (of which {list3.Count} are water)" : "")) : "") + "."));
				if (num3 == 0 && list.Count > 0)
				{
					Plugin.Log.LogWarning((object)"Every blade was outside the zones, so no grass will be visible. Either the zone volumes do not overlap the terrain surface, or they are too thin vertically - the containment test is 3D, not a footprint.");
				}
			}
		}

		private static bool Inside(List<Collider> zones, Vector3 point)
		{
			//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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//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)
			foreach (Collider zone in zones)
			{
				if ((Object)(object)zone == (Object)null)
				{
					continue;
				}
				Bounds bounds = zone.bounds;
				if (((Bounds)(ref bounds)).Contains(point))
				{
					MeshCollider val = (MeshCollider)(object)((zone is MeshCollider) ? zone : null);
					if (val != null && !val.convex)
					{
						return true;
					}
					Vector3 val2 = zone.ClosestPoint(point) - point;
					if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static List<Collider> WaterVolumes(Scene scene)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			List<Collider> list = new List<Collider>();
			QuicksandTrigger[] array = Resources.FindObjectsOfTypeAll<QuicksandTrigger>();
			foreach (QuicksandTrigger val in array)
			{
				if (!((Object)(object)val == (Object)null) && val.isWater && !(((Component)val).gameObject.scene != scene) && ((Component)val).gameObject.activeInHierarchy)
				{
					Collider component = ((Component)val).GetComponent<Collider>();
					if (!((Object)(object)component == (Object)null) && component.enabled)
					{
						list.Add(component);
					}
				}
			}
			return list;
		}

		private static List<Collider> Zones(SpawnGrassOnMesh grass, string prefix, ref List<Collider> cache)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			int sceneCount = SceneManager.sceneCount;
			if (cache != null && zonesForSceneCount == sceneCount)
			{
				return cache;
			}
			Scene scene = ((Component)grass).gameObject.scene;
			List<Collider> list = new List<Collider>();
			zonesForSceneCount = sceneCount;
			int num = 0;
			Collider[] array = Resources.FindObjectsOfTypeAll<Collider>();
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null) && !(((Component)val).gameObject.scene != scene) && ((Object)((Component)val).gameObject).name.StartsWith(prefix, StringComparison.Ordinal))
				{
					if (!val.enabled || !((Component)val).gameObject.activeInHierarchy)
					{
						num++;
					}
					else
					{
						list.Add(val);
					}
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogWarning((object)($"Ignoring {num} disabled or inactive '{prefix}*' volume(s) in " + "'" + ((Scene)(ref scene)).name + "'; their bounds cannot be trusted."));
			}
			Plugin.Log.LogInfo((object)((list.Count == 0) ? ("No '" + prefix + "*' volumes in '" + ((Scene)(ref scene)).name + "'.") : ($"Found {list.Count} '{prefix}*' volume(s) in '{((Scene)(ref scene)).name}': " + string.Join(", ", list.Select((Collider z) => ((Object)((Component)z).gameObject).name)))));
			cache = list;
			return cache;
		}
	}
	[HarmonyPatch]
	internal static class GrassPatches
	{
		[HarmonyPrefix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(SpawnGrassOnMesh), "Start")]
		private static void Start_Prefix(SpawnGrassOnMesh __instance)
		{
			try
			{
				GrassRuntime.BeforeStart(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Grass pre-spawn pass threw: {arg}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(SpawnGrassOnMesh), "Start")]
		private static void Start_Postfix(SpawnGrassOnMesh __instance)
		{
			try
			{
				GrassRuntime.AfterStart(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Grass post-spawn pass threw: {arg}");
			}
		}
	}
	[BepInPlugin("com.luth.27trudge", "27Trudge", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.luth.27trudge";

		public const string Name = "27Trudge";

		public const string Version = "1.0.0";

		internal static ConfigEntry<bool> RedirectMarchSceneOverride;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			RedirectMarchSceneOverride = ((BaseUnityPlugin)this).Config.Bind<bool>("RebalancedMoons", "RedirectMarchSceneOverride", true, "When RebalancedMoons is installed and its own March Scene Overrides is enabled, replaces Trudge's scene with rebalanced March instead of vanilla's. Still respects the Grass config.");
			try
			{
				GrassRuntime.Bind(((BaseUnityPlugin)this).Config);
				ReMarchGrass.Bind();
				Harmony val = new Harmony("com.luth.27trudge");
				val.PatchAll(typeof(MarchRedirectPatches));
				val.PatchAll(typeof(GrassPatches));
				RebalancedMoonsRedirect.SuppressMarchOverride();
				Log.LogInfo((object)("27Trudge 1.0.0 loaded. The moon is registered from its bundle; this plugin handles the RebalancedMoons redirect (" + (RedirectMarchSceneOverride.Value ? "enabled" : "disabled") + "), grass (" + (GrassRuntime.Enabled.Value ? "enabled" : "disabled") + "), and grass on 'ReMarchScene' when the redirect is active."));
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Failed to apply patches; the RebalancedMoons redirect will not run. {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal static class MarchRedirectPatches
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		private static void StartOfRound_Awake_Prefix(StartOfRound __instance)
		{
			if (!Plugin.RedirectMarchSceneOverride.Value)
			{
				return;
			}
			try
			{
				RebalancedMoonsRedirect.SnapshotMarch(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Recording vanilla March threw; the redirect will not run. {arg}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(StartOfRound), "Awake")]
		private static void StartOfRound_Awake_Postfix()
		{
			if (!Plugin.RedirectMarchSceneOverride.Value)
			{
				return;
			}
			try
			{
				RebalancedMoonsRedirect.TryRedirect();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)("The RebalancedMoons redirect threw; both moons are left as they " + $"were. {arg}"));
			}
		}
	}
	internal static class RebalancedMoonsRedirect
	{
		private sealed class MarchSnapshot
		{
			internal string SceneName;

			internal IntWithRarity[] DungeonFlowTypes;

			internal RandomWeatherWithVariables[] RandomWeathers;

			internal int RoutePrice = -1;

			internal bool Taken;
		}

		internal const string RebalancedMoonsGuid = "dopadream.lethalcompany.rebalancedmoons";

		private const string ConfigSection = "Server";

		private const string ConfigKey = "March Scene Overrides";

		private const string RebalancedMarchScene = "ReMarchScene";

		private const string VanillaMarchScene = "Level4March";

		private static readonly MarchSnapshot Snapshot = new MarchSnapshot();

		private static ExtendedLevel trudge;

		private static ExtendedLevel march;

		internal static bool RedirectWanted { get; private set; }

		internal static bool RedirectApplied { get; private set; }

		internal static void SnapshotMarch(StartOfRound instance)
		{
			if (!Snapshot.Taken)
			{
				SelectableLevel val = FindVanillaMarch(instance);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"Could not find vanilla March among StartOfRound.levels, so its original data cannot be recorded. The redirect will not run.");
					return;
				}
				Snapshot.SceneName = val.sceneName;
				Snapshot.DungeonFlowTypes = val.dungeonFlowTypes?.ToArray();
				Snapshot.RandomWeathers = val.randomWeathers?.ToArray();
				Snapshot.Taken = true;
				ManualLogSource log = Plugin.Log;
				string[] obj = new string[5] { "Recorded vanilla March: scene '", Snapshot.SceneName, "', ", null, null };
				IntWithRarity[] dungeonFlowTypes = Snapshot.DungeonFlowTypes;
				obj[3] = $"{((dungeonFlowTypes != null) ? dungeonFlowTypes.Length : 0)} dungeon flow(s), ";
				RandomWeatherWithVariables[] randomWeathers = Snapshot.RandomWeathers;
				obj[4] = $"{((randomWeathers != null) ? randomWeathers.Length : 0)} weather(s).";
				log.LogInfo((object)string.Concat(obj));
			}
		}

		internal static void TryRedirect()
		{
			if (!RedirectWanted)
			{
				return;
			}
			if (!Snapshot.Taken)
			{
				Plugin.Log.LogError((object)"March's vanilla data was never recorded, so redirecting would leave no way to restore it. Refusing - 61 March and Trudge are unchanged.");
				return;
			}
			trudge = FindExtendedLevel("27 Trudge");
			march = FindExtendedLevel("March", trudge);
			if ((Object)(object)trudge == (Object)null || (Object)(object)march == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Need both levels to redirect and found " + (((Object)(object)trudge == (Object)null) ? "no Trudge" : "Trudge") + " / " + (((Object)(object)march == (Object)null) ? "no March" : "March") + ". Nothing changed."));
				return;
			}
			if (!PatchedContent.AllLevelSceneNames.Contains("ReMarchScene"))
			{
				Plugin.Log.LogError((object)("'ReMarchScene' is not among LethalLevelLoader's loaded scene names, so pointing Trudge at it would make the moon unroutable. Refusing. Loaded scenes: " + string.Join(", ", PatchedContent.AllLevelSceneNames)));
				return;
			}
			string sceneName = march.SelectableLevel.sceneName;
			string text = Describe(march.SceneSelections);
			SelectableLevel selectableLevel = trudge.SelectableLevel;
			selectableLevel.sceneName = "ReMarchScene";
			Replace(trudge.SceneSelections, "ReMarchScene");
			selectableLevel.dungeonFlowTypes = march.SelectableLevel.dungeonFlowTypes?.ToArray() ?? selectableLevel.dungeonFlowTypes;
			selectableLevel.randomWeathers = march.SelectableLevel.randomWeathers?.ToArray() ?? selectableLevel.randomWeathers;
			int routePrice = march.RoutePrice;
			if (Snapshot.RoutePrice < 0)
			{
				Snapshot.RoutePrice = routePrice;
			}
			trudge.RoutePrice = routePrice;
			RedirectApplied = true;
			SelectableLevel selectableLevel2 = march.SelectableLevel;
			selectableLevel2.sceneName = Snapshot.SceneName ?? "Level4March";
			Replace(march.SceneSelections, selectableLevel2.sceneName);
			if (Snapshot.DungeonFlowTypes != null)
			{
				selectableLevel2.dungeonFlowTypes = Snapshot.DungeonFlowTypes.ToArray();
			}
			if (Snapshot.RandomWeathers != null)
			{
				selectableLevel2.randomWeathers = Snapshot.RandomWeathers.ToArray();
			}
			ManualLogSource log = Plugin.Log;
			string[] obj = new string[16]
			{
				"Redirected RebalancedMoons' March override to '", selectableLevel.PlanetName, "'.\n  Trudge scene   : 'ReMarchScene' (was 'Level4March' or the bundled Level27Trudge)\n", null, null, null, null, null, null, null,
				null, null, null, null, null, null
			};
			IntWithRarity[] dungeonFlowTypes = selectableLevel.dungeonFlowTypes;
			obj[3] = $"  Trudge gains   : {((dungeonFlowTypes != null) ? dungeonFlowTypes.Length : 0)} dungeon flow(s), ";
			RandomWeatherWithVariables[] randomWeathers = selectableLevel.randomWeathers;
			obj[4] = $"{((randomWeathers != null) ? randomWeathers.Length : 0)} weather(s), route price {routePrice}\n";
			obj[5] = "  Trudge keeps   : its pre-v80 enemy and scrap tables\n  March scene    : '";
			obj[6] = selectableLevel2.sceneName;
			obj[7] = "' (was '";
			obj[8] = sceneName;
			obj[9] = "')\n  March selections: ";
			obj[10] = text;
			obj[11] = " -> ";
			obj[12] = Describe(march.SceneSelections);
			obj[13] = "\n";
			IntWithRarity[] dungeonFlowTypes2 = selectableLevel2.dungeonFlowTypes;
			obj[14] = $"  March restored : {((dungeonFlowTypes2 != null) ? dungeonFlowTypes2.Length : 0)} dungeon flow(s), ";
			RandomWeatherWithVariables[] randomWeathers2 = selectableLevel2.randomWeathers;
			obj[15] = $"{((randomWeathers2 != null) ? randomWeathers2.Length : 0)} weather(s)";
			log.LogInfo((object)string.Concat(obj));
			if (string.Equals(sceneName, selectableLevel2.sceneName, StringComparison.Ordinal) && text == Describe(march.SceneSelections))
			{
				Plugin.Log.LogInfo((object)"March was still vanilla at this point, so RebalancedMoons applies its override later than this postfix - which is why its setting is switched off at source instead, at plugin load, rather than corrected here.");
			}
		}

		internal static void SuppressMarchOverride()
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			if (!Plugin.RedirectMarchSceneOverride.Value)
			{
				return;
			}
			if (!TryFindRebalancedMoons(out var info, out var guid))
			{
				Plugin.Log.LogInfo((object)("RebalancedMoons is not installed; nothing to redirect. Looked for " + string.Format("'{0}' among {1} loaded plugin(s).", "dopadream.lethalcompany.rebalancedmoons", Chainloader.PluginInfos.Count)));
			}
			else
			{
				if (!TryReadMarchOverrideSetting(info, guid, out var enabled))
				{
					return;
				}
				RedirectWanted = enabled;
				if (!enabled)
				{
					Plugin.Log.LogInfo((object)"RebalancedMoons is installed but 'March Scene Overrides' is off, so March is already vanilla and Trudge keeps its own scene. Nothing to do.");
					return;
				}
				BaseUnityPlugin instance = info.Instance;
				ConfigFile val = ((instance != null) ? instance.Config : null);
				ConfigEntry<bool> val2 = default(ConfigEntry<bool>);
				if (val == null || !val.TryGetEntry<bool>(new ConfigDefinition("Server", "March Scene Overrides"), ref val2))
				{
					Plugin.Log.LogWarning((object)"Could not reach RebalancedMoons' live config entry, so its March override cannot be switched off at source. Trudge will still be pointed at the rebalanced scene, but 61 March will ALSO be overridden - the two will look the same.");
					return;
				}
				bool saveOnConfigSet = val.SaveOnConfigSet;
				try
				{
					val.SaveOnConfigSet = false;
					val2.Value = false;
				}
				finally
				{
					val.SaveOnConfigSet = saveOnConfigSet;
				}
				Plugin.Log.LogInfo((object)"Turned RebalancedMoons' 'Server/March Scene Overrides' off for this session so 61 March stays vanilla; its config file is untouched. Trudge will take the rebalanced March instead. Set RedirectMarchSceneOverride=false to leave both mods alone.");
			}
		}

		private static bool TryFindRebalancedMoons(out PluginInfo info, out string guid)
		{
			if (Chainloader.PluginInfos.TryGetValue("dopadream.lethalcompany.rebalancedmoons", out info) && info != null)
			{
				guid = "dopadream.lethalcompany.rebalancedmoons";
				return true;
			}
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				if (pluginInfo.Key == null || pluginInfo.Value == null || pluginInfo.Key.IndexOf("rebalancedmoons", StringComparison.OrdinalIgnoreCase) < 0)
				{
					continue;
				}
				info = pluginInfo.Value;
				guid = pluginInfo.Key;
				Plugin.Log.LogWarning((object)("Found RebalancedMoons under GUID '" + guid + "', not the expected 'dopadream.lethalcompany.rebalancedmoons'. Proceeding, but the constant should be updated."));
				return true;
			}
			info = null;
			guid = null;
			return false;
		}

		private static bool TryReadMarchOverrideSetting(PluginInfo info, string guid, out bool enabled)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			enabled = false;
			BaseUnityPlugin instance = info.Instance;
			ConfigFile val = ((instance != null) ? instance.Config : null);
			if (val == null)
			{
				Plugin.Log.LogWarning((object)("RebalancedMoons ('" + guid + "') is loaded but its plugin instance is not reachable, so its live config cannot be read. Falling back to its config file."));
			}
			else
			{
				ConfigEntry<bool> val2 = default(ConfigEntry<bool>);
				if (val.TryGetEntry<bool>(new ConfigDefinition("Server", "March Scene Overrides"), ref val2))
				{
					enabled = val2.Value;
					Plugin.Log.LogInfo((object)string.Format("RebalancedMoons '{0}/{1}' = {2} (live config).", "Server", "March Scene Overrides", enabled));
					return true;
				}
				Plugin.Log.LogInfo((object)("RebalancedMoons has not bound 'Server/March Scene Overrides' in memory " + $"({val.Keys.Count()} setting(s) bound). Reading its config file instead."));
			}
			return TryReadSettingFromDisk(guid, out enabled);
		}

		private static bool TryReadSettingFromDisk(string guid, out bool enabled)
		{
			enabled = false;
			string text = Path.Combine(Paths.ConfigPath, guid + ".cfg");
			if (!File.Exists(text))
			{
				Plugin.Log.LogWarning((object)("No config file at '" + text + "', so RebalancedMoons' March setting cannot be read. Not redirecting."));
				return false;
			}
			string a = null;
			string[] array = File.ReadAllLines(text);
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.Length == 0 || text3[0] == '#')
				{
					continue;
				}
				if (text3[0] == '[')
				{
					a = text3.Trim('[', ']');
				}
				else if (string.Equals(a, "Server", StringComparison.OrdinalIgnoreCase))
				{
					int num = text3.IndexOf('=');
					if (num > 0 && string.Equals(text3.Substring(0, num).Trim(), "March Scene Overrides", StringComparison.OrdinalIgnoreCase) && bool.TryParse(text3.Substring(num + 1).Trim(), out enabled))
					{
						Plugin.Log.LogInfo((object)(string.Format("RebalancedMoons '{0}/{1}' = {2} ", "Server", "March Scene Overrides", enabled) + "(read from " + Path.GetFileName(text) + ")."));
						return true;
					}
				}
			}
			Plugin.Log.LogWarning((object)("'Server/March Scene Overrides' is not in " + Path.GetFileName(text) + " - it has probably been renamed. Not redirecting."));
			return false;
		}

		private static void Replace(List<StringWithRarity> selections, string sceneName)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			if (selections != null)
			{
				selections.Clear();
				selections.Add(new StringWithRarity(sceneName, 300));
			}
		}

		private static string Describe(List<StringWithRarity> selections)
		{
			return (selections == null || selections.Count == 0) ? "<none>" : string.Join(" + ", selections.Select((StringWithRarity s) => $"{s.Name}({s.Rarity})"));
		}

		private static SelectableLevel FindVanillaMarch(StartOfRound instance)
		{
			return instance?.levels?.FirstOrDefault((Func<SelectableLevel, bool>)((SelectableLevel l) => (Object)(object)l != (Object)null && string.Equals(l.sceneName, "Level4March", StringComparison.Ordinal)));
		}

		private static ExtendedLevel FindExtendedLevel(string planetNameFragment, ExtendedLevel exclude = null)
		{
			foreach (ExtendedLevel extendedLevel in PatchedContent.ExtendedLevels)
			{
				if (!((Object)(object)extendedLevel == (Object)null) && !((Object)(object)extendedLevel == (Object)(object)exclude) && !((Object)(object)extendedLevel.SelectableLevel == (Object)null))
				{
					string planetName = extendedLevel.SelectableLevel.PlanetName;
					if (!string.IsNullOrEmpty(planetName) && planetName.IndexOf(planetNameFragment, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return extendedLevel;
					}
				}
			}
			return null;
		}
	}
	internal static class ReMarchGrass
	{
		internal const string SceneName = "ReMarchScene";

		private const string KitName = "TrudgeGrassKit";

		private const string HostName = "TrudgeGrassHost";

		private const string KitInstanceName = "TrudgeGrassZones";

		internal static void Bind()
		{
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (((Scene)(ref scene)).name != "ReMarchScene")
			{
				return;
			}
			try
			{
				Inject(scene);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)("Adding grass to 'ReMarchScene' threw; their scene is untouched " + $"apart from anything already added. {arg}"));
			}
		}

		private static void Inject(Scene scene)
		{
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Expected O, but got Unknown
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.RedirectMarchSceneOverride.Value || !RebalancedMoonsRedirect.RedirectWanted)
			{
				Plugin.Log.LogInfo((object)"'ReMarchScene' loaded but the redirect is not active, so this is RebalancedMoons rendering their own March. Leaving it alone.");
				return;
			}
			if (!GrassRuntime.Enabled.Value)
			{
				Plugin.Log.LogInfo((object)"Grass is disabled by config, so 'ReMarchScene' gets none.");
				return;
			}
			GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects();
			if (rootGameObjects.Any((GameObject r) => ((Object)r).name == "TrudgeGrassZones") || rootGameObjects.SelectMany((GameObject r) => r.GetComponentsInChildren<Transform>(true)).Any((Transform t) => ((Object)t).name == "TrudgeGrassHost"))
			{
				Plugin.Log.LogInfo((object)"'ReMarchScene' already has our grass; not adding it twice.");
				return;
			}
			GameObject val = FindKit();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Could not find the 'TrudgeGrassKit' prefab in memory or in any of the " + string.Format("{0} loaded bundle(s), so '{1}' ", AssetBundle.GetAllLoadedAssetBundles().Count(), "ReMarchScene") + "gets no grass. It ships in 27trudgemoon.lethalbundle - run editor step 6 and then step 2 if it is missing."));
				return;
			}
			SpawnGrassOnMesh component = val.GetComponent<SpawnGrassOnMesh>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogWarning((object)"The 'TrudgeGrassKit' prefab has no SpawnGrassOnMesh to copy settings from, so 'ReMarchScene' gets no grass.");
				return;
			}
			MeshCollider val2 = FindTerrain(rootGameObjects);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No MeshCollider in 'ReMarchScene' looks like a terrain, so there is nothing to grow grass on.");
				return;
			}
			GameObject val3 = Object.Instantiate<GameObject>(val, Vector3.zero, Quaternion.identity);
			((Object)val3).name = "TrudgeGrassZones";
			SceneManager.MoveGameObjectToScene(val3, scene);
			SpawnGrassOnMesh component2 = val3.GetComponent<SpawnGrassOnMesh>();
			if ((Object)(object)component2 != (Object)null)
			{
				Object.Destroy((Object)(object)component2);
			}
			GameObject val4 = new GameObject("TrudgeGrassHost");
			val4.transform.SetParent(((Component)val2).transform, false);
			val4.transform.localPosition = Vector3.zero;
			val4.transform.localRotation = Quaternion.identity;
			val4.transform.localScale = Vector3.one;
			val4.layer = ((Component)val2).gameObject.layer;
			Mesh sharedMesh = val2.sharedMesh;
			if ((Object)(object)sharedMesh == (Object)null || !sharedMesh.isReadable)
			{
				Plugin.Log.LogWarning((object)("'" + ((Object)((Component)val2).gameObject).name + "' has " + (((Object)(object)sharedMesh == (Object)null) ? "no collider mesh" : ("a collider mesh ('" + ((Object)sharedMesh).name + "') that is not Read/Write enabled")) + ", and the spawner reads its vertices. No grass on 'ReMarchScene'."));
				Object.Destroy((Object)(object)val4);
				Object.Destroy((Object)(object)val3);
				return;
			}
			val4.AddComponent<MeshFilter>().sharedMesh = sharedMesh;
			SpawnGrassOnMesh val5 = val4.AddComponent<SpawnGrassOnMesh>();
			val5.mesh = component.mesh;
			val5.material = component.material;
			val5.terrainMeshBounds = (Collider)(object)val2;
			val5.onlyRenderOutdoors = component.onlyRenderOutdoors;
			val5.spawnManually = component.spawnManually;
			val5.numberOfBlades = component.numberOfBlades;
			val5.minScale = component.minScale;
			val5.maxScale = component.maxScale;
			val5.minVerticalScale = component.minVerticalScale;
			val5.spawnOffset = component.spawnOffset;
			val5.maxSlope = component.maxSlope;
			val5.chunkDrawDistance = component.chunkDrawDistance;
			val5.cellSize = component.cellSize;
			Collider[] componentsInChildren = val3.GetComponentsInChildren<Collider>(true);
			Bounds b = ((Collider)val2).bounds;
			Plugin.Log.LogInfo((object)("Added grass to 'ReMarchScene'.\n  terrain    : '" + ((Object)((Component)val2).gameObject).name + "', mesh '" + ((Object)sharedMesh).name + "', " + $"world x[{((Bounds)(ref b)).min.x:F0},{((Bounds)(ref b)).max.x:F0}] z[{((Bounds)(ref b)).min.z:F0},{((Bounds)(ref b)).max.z:F0}]\n" + string.Format("  host       : '{0}' under it, non-static, {1} verts to scatter over\n", "TrudgeGrassHost", sharedMesh.vertexCount) + string.Format("  volumes    : {0} ({1})\n", componentsInChildren.Length, string.Join(", ", componentsInChildren.Select((Collider v) => ((Object)((Component)v).gameObject).name))) + $"  blades     : {val5.numberOfBlades}, cell {val5.cellSize}, slope <= {val5.maxSlope}\n" + "  GrassRuntime's Start() postfix does the shader rebind and the zone filtering from here, and reports how many blades survived."));
			int num = componentsInChildren.Count(delegate(Collider v)
			{
				//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_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: 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_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: 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_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				Bounds bounds = v.bounds;
				int result;
				if (((Bounds)(ref bounds)).min.x < ((Bounds)(ref b)).max.x)
				{
					bounds = v.bounds;
					if (((Bounds)(ref bounds)).max.x > ((Bounds)(ref b)).min.x)
					{
						bounds = v.bounds;
						if (((Bounds)(ref bounds)).min.z < ((Bounds)(ref b)).max.z)
						{
							bounds = v.bounds;
							result = ((((Bounds)(ref bounds)).max.z > ((Bounds)(ref b)).min.z) ? 1 : 0);
							goto IL_0097;
						}
					}
				}
				result = 0;
				goto IL_0097;
				IL_0097:
				return (byte)result != 0;
			});
			if (num < componentsInChildren.Length)
			{
				Plugin.Log.LogWarning((object)($"Only {num} of {componentsInChildren.Length} grass zones overlap this terrain's bounds, so " + "RebalancedMoons' March is not laid out where Trudge's zones were authored. Grass will be sparse or absent. The zones would need authoring separately for their scene."));
			}
		}

		private static GameObject FindKit()
		{
			GameObject val = ((IEnumerable<GameObject>)Resources.FindObjectsOfTypeAll<GameObject>()).FirstOrDefault((Func<GameObject, bool>)delegate(GameObject g)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				int result;
				if ((Object)(object)g != (Object)null && string.Equals(((Object)g).name, "TrudgeGrassKit", StringComparison.Ordinal))
				{
					Scene scene = g.scene;
					result = ((!((Scene)(ref scene)).IsValid()) ? 1 : 0);
				}
				else
				{
					result = 0;
				}
				return (byte)result != 0;
			});
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			string suffix = "/" + "TrudgeGrassKit".ToLowerInvariant() + ".prefab";
			foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
			{
				if ((Object)(object)allLoadedAssetBundle == (Object)null)
				{
					continue;
				}
				string text;
				try
				{
					text = allLoadedAssetBundle.GetAllAssetNames().FirstOrDefault((string n) => n.EndsWith(suffix, StringComparison.OrdinalIgnoreCase));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogDebug((object)("Skipped bundle '" + ((Object)allLoadedAssetBundle).name + "' while looking for the grass kit: " + ex.GetType().Name + "."));
					continue;
				}
				if (text != null)
				{
					GameObject val2 = allLoadedAssetBundle.LoadAsset<GameObject>(text);
					if (!((Object)(object)val2 == (Object)null))
					{
						Plugin.Log.LogInfo((object)("Loaded the grass kit from bundle '" + ((Object)allLoadedAssetBundle).name + "' ('" + text + "'). It is in the bundle but nothing referenced it, so it was not in memory yet."));
						return val2;
					}
				}
			}
			return null;
		}

		private static MeshCollider FindTerrain(GameObject[] roots)
		{
			return (from c in roots.SelectMany((GameObject r) => r.GetComponentsInChildren<MeshCollider>(true))
				where (Object)(object)c != (Object)null && ((Collider)c).enabled && (Object)(object)c.sharedMesh != (Object)null
				where ((Object)((Component)c).gameObject).name.IndexOf("OutOfBounds", StringComparison.OrdinalIgnoreCase) < 0
				select c).OrderByDescending(delegate(MeshCollider c)
			{
				//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_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				Bounds bounds = ((Collider)c).bounds;
				float x = ((Bounds)(ref bounds)).size.x;
				bounds = ((Collider)c).bounds;
				return x * ((Bounds)(ref bounds)).size.z;
			}).FirstOrDefault();
		}
	}
	internal static class TrudgeData
	{
		internal const string PlanetName = "27 Trudge";

		internal const string PlaceholderSceneName = "Level4March";
	}
}