Decompiled source of NadirRandomFix v1.0.2

NadirMod.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core;

[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("NadirMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NadirMod")]
[assembly: AssemblyTitle("NadirMod")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace NadirMod
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "NadirMod";

		public const string PLUGIN_NAME = "NadirMod";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace TrueFinalAscentNadirFix
{
	[BepInPlugin("com.custom.peak.truefinalascent.nadirfix", "True Final Ascent - Procedural Nadir Fix", "1.0.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class NadirFixPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "com.custom.peak.truefinalascent.nadirfix";

		public const string ModName = "True Final Ascent - Procedural Nadir Fix";

		public const string ModVersion = "1.0.4";

		internal static ManualLogSource Log;

		private Harmony? _harmony;

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("com.custom.peak.truefinalascent.nadirfix");
			_harmony.PatchAll();
			Log.LogInfo((object)"[True Final Ascent - Procedural Nadir Fix] loaded successfully (v1.0.4).");
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	public static class NadirGenerator
	{
		private const string Tag = "[NadirFix]";

		public static bool IsGeneratingNadir;

		private static bool _generatedThisScene;

		public static bool HasGenerated => _generatedThisScene;

		static NadirGenerator()
		{
			IsGeneratingNadir = false;
			_generatedThisScene = false;
			SceneManager.sceneLoaded += delegate
			{
				_generatedThisScene = false;
			};
		}

		public static bool HasUnpackedNadirFromHost()
		{
			GameObject val = FindVoidRoot();
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (((Object)componentsInChildren[i]).name.EndsWith("(Clone)"))
				{
					_generatedThisScene = true;
					return true;
				}
			}
			return false;
		}

		public static GameObject? FindVoidRoot()
		{
			try
			{
				Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscentVoid");
				if (type != null)
				{
					MethodInfo methodInfo = AccessTools.Method(type, "Find", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						object? obj = methodInfo.Invoke(null, null);
						GameObject val = (GameObject)((obj is GameObject) ? obj : null);
						if ((Object)(object)val != (Object)null)
						{
							return val;
						}
					}
				}
			}
			catch
			{
			}
			VoidBiome[] array = Object.FindObjectsByType<VoidBiome>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			VoidBiome[] array2 = array;
			foreach (VoidBiome val2 in array2)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					return ((Component)val2).gameObject;
				}
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				for (int j = 0; j < ((Component)instance).transform.childCount; j++)
				{
					Transform child = ((Component)instance).transform.GetChild(j);
					if (((Object)child).name.IndexOf("VOID", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return ((Component)child).gameObject;
					}
				}
			}
			return GameObject.Find("VOID");
		}

		public static void SetVoidBiomeActive(bool active)
		{
			GameObject val = FindVoidRoot();
			if ((Object)(object)val != (Object)null && val.activeSelf != active)
			{
				val.SetActive(active);
			}
			try
			{
				MethodInfo methodInfo = AccessTools.Property(typeof(VoidBiome), "VoidBiomeActive")?.GetSetMethod(nonPublic: true);
				if (methodInfo != null)
				{
					methodInfo.Invoke(null, new object[1] { active });
					return;
				}
				FieldInfo fieldInfo = AccessTools.Field(typeof(VoidBiome), "VoidBiomeActive") ?? AccessTools.Field(typeof(VoidBiome), "_voidBiomeActive") ?? AccessTools.Field(typeof(VoidBiome), "m_VoidBiomeActive") ?? AccessTools.Field(typeof(VoidBiome), "<VoidBiomeActive>k__BackingField");
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(null, active);
				}
			}
			catch
			{
			}
		}

		public static int GetCurrentSeed()
		{
			try
			{
				Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscent");
				if (type != null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(type, "Seed");
					if (propertyInfo != null && propertyInfo.GetValue(null) is int num && num != 0)
					{
						return num;
					}
				}
			}
			catch
			{
			}
			try
			{
				if (PhotonNetwork.InRoom)
				{
					Room currentRoom = PhotonNetwork.CurrentRoom;
					if (((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null) != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"FAs", out object value) && value is int num2 && true && num2 != 0)
					{
						return num2;
					}
				}
			}
			catch
			{
			}
			try
			{
				LevelGeneration val = Object.FindFirstObjectByType<LevelGeneration>();
				if ((Object)(object)val != (Object)null)
				{
					FieldInfo fieldInfo = AccessTools.Field(typeof(LevelGeneration), "seed");
					if (fieldInfo != null && fieldInfo.GetValue(val) is int num3 && num3 != 0)
					{
						return num3;
					}
				}
			}
			catch
			{
			}
			return 1337;
		}

		public static bool IsFinalAscentActive()
		{
			try
			{
				Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscent");
				if (type != null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(type, "Active");
					if (propertyInfo != null && propertyInfo.GetValue(null) is bool result)
					{
						return result;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		public static bool IsInNadir()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			if (VoidBiome.VoidBiomeActive)
			{
				return true;
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				if (instance.inNadir)
				{
					return true;
				}
				if ((int)MapHandler.CurrentSegmentNumber == 6)
				{
					return true;
				}
			}
			try
			{
				if (PhotonNetwork.InRoom)
				{
					Room currentRoom = PhotonNetwork.CurrentRoom;
					if (((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null) != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"FAe", out object value) && value is int num && true && num >= 96)
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		public static void GenerateNadir(int baseSeed)
		{
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Invalid comparison between Unknown and I4
			if (_generatedThisScene)
			{
				NadirFixPlugin.Log.LogInfo((object)"[NadirFix] Nadir already generated for this scene; skipping.");
				return;
			}
			GameObject val = FindVoidRoot();
			if ((Object)(object)val == (Object)null)
			{
				NadirFixPlugin.Log.LogWarning((object)"[NadirFix] Void root could not be located; aborting Nadir generation.");
				return;
			}
			NadirFixPlugin.Log.LogInfo((object)string.Format("{0} Beginning procedural generation for Nadir with seed {1}...", "[NadirFix]", baseSeed));
			List<GameObject> disabled = new List<GameObject>();
			IsolateVoid(val, disabled);
			try
			{
				IsGeneratingNadir = true;
				bool activeSelf = val.activeSelf;
				val.SetActive(true);
				EnablingSubstep[] componentsInChildren = val.GetComponentsInChildren<EnablingSubstep>(true);
				EnablingSubstep[] array = componentsInChildren;
				foreach (EnablingSubstep val2 in array)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						((Component)val2).gameObject.SetActive(true);
					}
				}
				Physics.SyncTransforms();
				int num = baseSeed ^ 0x4E414449;
				IGenConfigStep[] componentsInChildren2 = val.GetComponentsInChildren<IGenConfigStep>(true);
				for (int j = 0; j < componentsInChildren2.Length; j++)
				{
					if (componentsInChildren2[j] != null)
					{
						try
						{
							Random.InitState(num ^ (j * 31));
							componentsInChildren2[j].RunStep();
						}
						catch (Exception ex)
						{
							NadirFixPlugin.Log.LogWarning((object)("[NadirFix] IGenConfigStep " + ((object)componentsInChildren2[j]).GetType().Name + " failed: " + ex.Message));
						}
					}
				}
				LevelGenStep[] componentsInChildren3 = val.GetComponentsInChildren<LevelGenStep>(true);
				List<LevelGenStep> list = new List<LevelGenStep>();
				List<LevelGenStep> list2 = new List<LevelGenStep>();
				LevelGenStep[] array2 = componentsInChildren3;
				foreach (LevelGenStep val3 in array2)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						PropGrouper componentInParent = ((Component)val3).GetComponentInParent<PropGrouper>(true);
						if ((Object)(object)componentInParent != (Object)null && (int)componentInParent.timing == 1)
						{
							list2.Add(val3);
						}
						else
						{
							list.Add(val3);
						}
					}
				}
				LevelGenStep[] array3 = componentsInChildren3;
				foreach (LevelGenStep val4 in array3)
				{
					if ((Object)(object)val4 != (Object)null)
					{
						try
						{
							val4.Clear();
						}
						catch
						{
						}
					}
				}
				Physics.SyncTransforms();
				List<IDeferredStep> list3 = new List<IDeferredStep>();
				ExecuteStepBatch(list, num, list3);
				Physics.SyncTransforms();
				RunDeferredBatch(list3);
				list3.Clear();
				Physics.SyncTransforms();
				ExecuteStepBatch(list2, num, list3);
				Physics.SyncTransforms();
				RunDeferredBatch(list3);
				list3.Clear();
				Physics.SyncTransforms();
				ILevelGenFinalizer[] componentsInChildren4 = val.GetComponentsInChildren<ILevelGenFinalizer>(true);
				ILevelGenFinalizer[] array4 = componentsInChildren4;
				foreach (ILevelGenFinalizer val5 in array4)
				{
					if (val5 != null)
					{
						try
						{
							val5.OnLevelGenFinished();
						}
						catch (Exception ex2)
						{
							NadirFixPlugin.Log.LogWarning((object)("[NadirFix] Finalizer " + ((object)val5).GetType().Name + " threw: " + ex2.Message));
						}
					}
				}
				SpawnZone[] componentsInChildren5 = val.GetComponentsInChildren<SpawnZone>(true);
				SpawnZone[] array5 = componentsInChildren5;
				foreach (SpawnZone val6 in array5)
				{
					if ((Object)(object)val6 != (Object)null)
					{
						Collider[] components = ((Component)val6).GetComponents<Collider>();
						for (int num2 = 0; num2 < components.Length; num2++)
						{
							Object.Destroy((Object)(object)components[num2]);
						}
					}
				}
				val.SetActive(activeSelf);
				_generatedThisScene = true;
				NadirFixPlugin.Log.LogInfo((object)string.Format("{0} Successfully generated procedural Nadir ({1} level-gen steps executed).", "[NadirFix]", componentsInChildren3.Length));
			}
			catch (Exception arg)
			{
				NadirFixPlugin.Log.LogError((object)string.Format("{0} Error generating Nadir: {1}", "[NadirFix]", arg));
			}
			finally
			{
				IsGeneratingNadir = false;
				RestoreIsolation(disabled);
				Physics.SyncTransforms();
			}
		}

		private static void ExecuteStepBatch(List<LevelGenStep> batch, int baseSeed, List<IDeferredStep> deferredList)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Invalid comparison between Unknown and I4
			foreach (LevelGenStep item in batch)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				int num = baseSeed ^ StableHash(GetPath(((Component)item).transform));
				Random.InitState(num);
				try
				{
					item.Clear();
					IEnumerator enumerator2 = item.Execute();
					while (enumerator2 != null && enumerator2.MoveNext())
					{
					}
				}
				catch (Exception ex)
				{
					NadirFixPlugin.Log.LogWarning((object)("[NadirFix] Step '" + ((Object)item).name + "' failed: " + ex.Message));
				}
				if ((int)item.DeferredTiming > 0)
				{
					try
					{
						IDeferredStep val = item.ConstructDeferred((IMayHaveDeferredStep)(object)item);
						if (val != null)
						{
							deferredList.Add(val);
						}
					}
					catch
					{
					}
				}
				Physics.SyncTransforms();
			}
		}

		private static void RunDeferredBatch(List<IDeferredStep> deferredList)
		{
			foreach (IDeferredStep deferred in deferredList)
			{
				if (deferred != null)
				{
					try
					{
						deferred.DeferredGo();
					}
					catch (Exception ex)
					{
						NadirFixPlugin.Log.LogWarning((object)("[NadirFix] Deferred step failed: " + ex.Message));
					}
				}
			}
		}

		private static void IsolateVoid(GameObject voidRoot, List<GameObject> disabled)
		{
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				for (int i = 0; i < ((Component)instance).transform.childCount; i++)
				{
					Transform child = ((Component)instance).transform.GetChild(i);
					if ((Object)(object)((Component)child).gameObject != (Object)(object)voidRoot && ((Component)child).gameObject.activeSelf && !child.IsChildOf(voidRoot.transform))
					{
						((Component)child).gameObject.SetActive(false);
						disabled.Add(((Component)child).gameObject);
					}
				}
			}
			LevelGeneration val = Object.FindFirstObjectByType<LevelGeneration>();
			if (!((Object)(object)val != (Object)null))
			{
				return;
			}
			for (int j = 0; j < ((Component)val).transform.childCount; j++)
			{
				Transform child2 = ((Component)val).transform.GetChild(j);
				if ((Object)(object)((Component)child2).gameObject != (Object)(object)voidRoot && ((Component)child2).gameObject.activeSelf && !child2.IsChildOf(voidRoot.transform))
				{
					((Component)child2).gameObject.SetActive(false);
					disabled.Add(((Component)child2).gameObject);
				}
			}
		}

		private static void RestoreIsolation(List<GameObject> disabled)
		{
			foreach (GameObject item in disabled)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.SetActive(true);
				}
			}
		}

		private static int StableHash(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return 0;
			}
			uint num = 2166136261u;
			foreach (char c in text)
			{
				num = (num ^ c) * 16777619;
			}
			return (int)num;
		}

		private static string GetPath(Transform? t)
		{
			if ((Object)(object)t == (Object)null)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(((Object)t).name);
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null)
			{
				stringBuilder.Insert(0, '/').Insert(0, ((Object)parent).name);
				parent = parent.parent;
			}
			return stringBuilder.ToString();
		}
	}
	[HarmonyPatch]
	public static class Patch_FinalAscentVoidGuard
	{
		public static MethodBase? TargetMethod()
		{
			Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscentVoidGuard");
			return (type != null) ? AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null) : null;
		}

		[HarmonyPrefix]
		public static bool Prefix(ref bool __result)
		{
			__result = true;
			return false;
		}
	}
	[HarmonyPatch]
	public static class Patch_FinalAscentVoid_Wake
	{
		public static MethodBase? TargetMethod()
		{
			Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscentVoid");
			return (type != null) ? AccessTools.Method(type, "Wake", (Type[])null, (Type[])null) : null;
		}

		[HarmonyPostfix]
		public static void Postfix()
		{
			if (NadirGenerator.IsFinalAscentActive() && (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient))
			{
				int currentSeed = NadirGenerator.GetCurrentSeed();
				NadirGenerator.GenerateNadir(currentSeed);
			}
		}
	}
	[HarmonyPatch]
	public static class Patch_FinalAscentBuilder_MarkReady
	{
		public static MethodBase? TargetMethod()
		{
			Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscentBuilder");
			return (type != null) ? AccessTools.Method(type, "MarkReady", (Type[])null, (Type[])null) : null;
		}

		[HarmonyPrefix]
		public static void Prefix()
		{
			if (NadirGenerator.IsFinalAscentActive() && !NadirGenerator.HasGenerated && !NadirGenerator.HasUnpackedNadirFromHost())
			{
				int currentSeed = NadirGenerator.GetCurrentSeed();
				NadirGenerator.GenerateNadir(currentSeed);
			}
		}
	}
	[HarmonyPatch]
	public static class Patch_FixNadirSpawnPoint
	{
		public static MethodBase? TargetMethod()
		{
			Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscentBaseCampPatch");
			return (type != null) ? AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null) : null;
		}

		[HarmonyPrefix]
		public static bool Prefix(ref bool __result)
		{
			if (NadirGenerator.IsInNadir())
			{
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class Patch_FixNadirJumpGate
	{
		public static MethodBase? TargetMethod()
		{
			Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscentJumpGate");
			return (type != null) ? AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null) : null;
		}

		[HarmonyPrefix]
		public static bool Prefix(Segment newSegment, ref bool __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)newSegment == 6)
			{
				NadirGenerator.SetVoidBiomeActive(active: true);
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class Patch_FixNadirSoftLanding
	{
		public static MethodBase? TargetMethod()
		{
			Type type = AccessTools.TypeByName("TrueFinalAscent.FinalAscentSoftLanding");
			return (type != null) ? AccessTools.Method(type, "Begin", (Type[])null, (Type[])null) : null;
		}

		[HarmonyPrefix]
		public static bool Prefix()
		{
			if (NadirGenerator.IsInNadir())
			{
				NadirFixPlugin.Log.LogInfo((object)"[NadirFix] In Nadir: suppressed SoftLanding warp to mountain basecamp.");
				return false;
			}
			return true;
		}
	}
}