Decompiled source of LeucotomyCore v0.1.0

BepInEx/plugins/Leucotomy.ConstellationDawnBridge.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Dawn;
using HarmonyLib;
using LethalConstellations.PluginCore;
using LethalLevelLoader;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Leucotomy.Routing;

[BepInPlugin("leucotomy.compat.constellationsdawn", "Leucotomy Constellations Dawn Bridge", "0.2.1")]
[BepInDependency("com.github.darmuh.LethalConstellations", "0.3.3")]
[BepInDependency("com.github.teamxiaolan.dawnlib", "0.9.25")]
[BepInDependency("imabatby.lethallevelloader", "1.7.13")]
public sealed class RoutingBridge : BaseUnityPlugin
{
	private sealed class Binding
	{
		internal readonly DawnMoonInfo Info;

		internal ExtendedLevel Level;

		internal ITerminalPurchasePredicate OriginalPredicate;

		internal IProvider<int> OriginalPrice;

		internal readonly Guard Guard;

		internal readonly Price Price;

		internal int? LastLoggedPrice;

		internal Binding(DawnMoonInfo info, ExtendedLevel level)
		{
			Info = info;
			Level = level;
			Guard = new Guard(this);
			Price = new Price(this);
		}
	}

	private sealed class Guard : ITerminalPurchasePredicate
	{
		private readonly Binding binding;

		private TerminalNode denied;

		internal Guard(Binding binding)
		{
			this.binding = binding;
		}

		public TerminalPurchaseResult CanPurchase()
		{
			ExtendedLevel level = binding.Level;
			if (!InCurrentConstellation(level.NumberlessPlanetName))
			{
				return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Hidden().SetFailure(true);
			}
			TerminalPurchaseResult val = binding.OriginalPredicate.CanPurchase();
			if (level.IsRouteHidden)
			{
				HiddenPurchaseResult val2 = (HiddenPurchaseResult)(object)((val is HiddenPurchaseResult) ? val : null);
				bool flag = !(val is SuccessPurchaseResult) && (val2 == null || val2.IsFailure);
				return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Hidden().SetFailure(level.IsRouteLocked || flag);
			}
			if (level.IsRouteLocked)
			{
				if ((Object)(object)denied == (Object)null)
				{
					denied = ScriptableObject.CreateInstance<TerminalNode>();
				}
				denied.displayText = level.LockedRouteNodeText;
				denied.clearPreviousText = true;
				return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Fail(denied);
			}
			return val;
		}
	}

	private sealed class Price : IProvider<int>
	{
		private readonly Binding binding;

		internal Price(Binding binding)
		{
			this.binding = binding;
		}

		public int Provide()
		{
			if (!TryConfiguredPrice(binding.Level, out var value))
			{
				return binding.OriginalPrice.Provide();
			}
			return value;
		}
	}

	public const string Id = "leucotomy.compat.constellationsdawn";

	private static readonly FieldInfo PredicateField = AccessTools.Field(typeof(DawnPurchaseInfo), "<PurchasePredicate>k__BackingField");

	private static readonly FieldInfo CostField = AccessTools.Field(typeof(DawnPurchaseInfo), "<Cost>k__BackingField");

	private static readonly FieldInfo MoonPricesField = AccessTools.Field(typeof(Collections), "MoonPrices");

	private static readonly Type ConfigType = typeof(Collections).Assembly.GetType("LethalConstellations.ConfigManager.Configuration");

	private static readonly PropertyInfo ModifyPricesProperty = ConfigType.GetProperty("ModifyMoonPrices", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

	private static readonly Dictionary<DawnPurchaseInfo, Binding> Bound = new Dictionary<DawnPurchaseInfo, Binding>();

	private static ManualLogSource Log;

	private static bool syncing;

	private static int lastPending = -1;

	private Harmony harmony;

	private bool cleanedUp;

	private void Awake()
	{
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Expected O, but got Unknown
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e0: Expected O, but got Unknown
		//IL_022c: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		string[] array = new string[3] { "com.github.teamxiaolan.dawnlib", "imabatby.lethallevelloader", "com.github.darmuh.LethalConstellations" };
		string[] array2 = new string[3] { "0.9.25", "1.7.13", "0.3.3" };
		for (int i = 0; i < array.Length; i++)
		{
			if (Chainloader.PluginInfos[array[i]].Metadata.Version.ToString() != array2[i])
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Unsupported framework version; bridge NOT installed.");
				return;
			}
		}
		Type type = typeof(DawnPurchaseInfo).Assembly.GetType("Dawn.MoonRegistrationHandler", throwOnError: true);
		Type type2 = typeof(DawnPurchaseInfo).Assembly.GetType("Dawn.Internal.TerminalPatches", throwOnError: true);
		Type type3 = typeof(Collections).Assembly.GetType("LethalConstellations.PluginCore.MoonStuff", throwOnError: true);
		MethodInfo[] array3 = new MethodInfo[4]
		{
			AccessTools.Method(type, "UpdateAllPrices", (Type[])null, (Type[])null),
			AccessTools.Method(type, "DynamicMoonCatalogue", (Type[])null, (Type[])null),
			AccessTools.Method(type2, "HandlePredicate", (Type[])null, (Type[])null),
			AccessTools.Method(type3, "ModifyMoonPrices", (Type[])null, (Type[])null)
		};
		if (PredicateField == null || CostField == null || MoonPricesField == null || ModifyPricesProperty == null)
		{
			throw new InvalidOperationException("Reviewed backing fields/config contract absent.");
		}
		MethodInfo[] array4 = array3;
		foreach (MethodInfo methodInfo in array4)
		{
			if (methodInfo == null)
			{
				throw new MissingMethodException("Reviewed semantic hook missing.");
			}
		}
		harmony = new Harmony("leucotomy.compat.constellationsdawn");
		try
		{
			HarmonyMethod val = new HarmonyMethod(typeof(RoutingBridge).GetMethod("SyncPrefix", BindingFlags.Static | BindingFlags.NonPublic));
			harmony.Patch((MethodBase)array3[0], val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)array3[1], val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)array3[2], new HarmonyMethod(typeof(RoutingBridge).GetMethod("RoutePrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)array3[3], (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Application.quitting += Shutdown;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Bridge 0.2.1 hooks installed; process-lifetime cleanup; native bindings still PENDING.");
		}
		catch
		{
			harmony.UnpatchSelf();
			throw;
		}
	}

	private static void SyncPrefix()
	{
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Expected O, but got Unknown
		if (syncing)
		{
			return;
		}
		syncing = true;
		try
		{
			int num = 0;
			foreach (DawnMoonInfo value2 in ((Registry<DawnMoonInfo>)(object)LethalContent.Moons).Values)
			{
				if (value2 == null || (Object)(object)value2.Level == (Object)null || ((DawnBaseInfo<DawnMoonInfo>)(object)value2).Key.IsVanilla() || ((DawnBaseInfo<DawnMoonInfo>)(object)value2).HasTag(NamespacedKey.From("dawn_lib", "is_external")))
				{
					continue;
				}
				ExtendedLevel val = null;
				foreach (ExtendedLevel extendedLevel in PatchedContent.ExtendedLevels)
				{
					if (object.ReferenceEquals(extendedLevel.SelectableLevel, value2.Level))
					{
						val = extendedLevel;
						break;
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					num++;
					continue;
				}
				DawnPurchaseInfo dawnPurchaseInfo = value2.DawnPurchaseInfo;
				if (!Bound.TryGetValue(dawnPurchaseInfo, out var value))
				{
					value = new Binding(value2, val);
					Bound.Add(dawnPurchaseInfo, value);
				}
				value.Level = val;
				ITerminalPurchasePredicate val2 = (ITerminalPurchasePredicate)PredicateField.GetValue(dawnPurchaseInfo);
				if (!object.ReferenceEquals(val2, value.Guard))
				{
					value.OriginalPredicate = val2;
					PredicateField.SetValue(dawnPurchaseInfo, value.Guard);
					Log.LogInfo((object)("BOUND " + val.NumberlessPlanetName + " predicate-field verified=" + object.ReferenceEquals(PredicateField.GetValue(dawnPurchaseInfo), value.Guard)));
				}
				IProvider<int> val3 = (IProvider<int>)CostField.GetValue(dawnPurchaseInfo);
				if (!object.ReferenceEquals(val3, value.Price))
				{
					value.OriginalPrice = val3;
					CostField.SetValue(dawnPurchaseInfo, value.Price);
				}
				int num2 = value.Price.Provide();
				if (value.LastLoggedPrice != num2)
				{
					Log.LogInfo((object)("PRICE " + val.NumberlessPlanetName + " base=" + num2 + "; stored-provider verified=" + object.ReferenceEquals(CostField.GetValue(dawnPurchaseInfo), value.Price)));
					value.LastLoggedPrice = num2;
				}
			}
			if (num != lastPending)
			{
				Log.LogInfo((object)("Native bindings=" + Bound.Count + "; awaiting LLL registration=" + num));
				lastPending = num;
			}
		}
		finally
		{
			syncing = false;
		}
	}

	private static void RoutePrefix(ref TerminalNode node)
	{
		SyncPrefix();
		foreach (Binding value in Bound.Values)
		{
			if (object.ReferenceEquals(node, value.Info.RouteNode) || object.ReferenceEquals(node, value.Info.ReceiptNode))
			{
				TerminalPurchaseResult val = value.Guard.CanPurchase();
				FailedPurchaseResult val2 = (FailedPurchaseResult)(object)((val is FailedPurchaseResult) ? val : null);
				HiddenPurchaseResult val3 = (HiddenPurchaseResult)(object)((val is HiddenPurchaseResult) ? val : null);
				if (val2 != null || (val3 != null && val3.IsFailure))
				{
					Log.LogInfo((object)("DENIED " + value.Level.NumberlessPlanetName + " in " + Collections.CurrentConstellation + " (preview or confirm)"));
					node = ((val2 != null) ? val2.ReasonNode : val3.ReasonNode);
				}
				else
				{
					Log.LogInfo((object)("ALLOWED " + value.Level.NumberlessPlanetName + " in " + Collections.CurrentConstellation + "; base price=" + value.Price.Provide()));
				}
				break;
			}
		}
	}

	private static bool InCurrentConstellation(string moon)
	{
		foreach (ClassMapper item in Collections.ConstellationStuff)
		{
			if (!string.Equals(item.consName, Collections.CurrentConstellation, StringComparison.OrdinalIgnoreCase))
			{
				continue;
			}
			foreach (string constelMoon in item.constelMoons)
			{
				if (string.Equals(constelMoon, moon, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
		}
		return false;
	}

	private static bool TryConfiguredPrice(ExtendedLevel level, out int value)
	{
		value = 0;
		ConfigEntry<bool> val = (ConfigEntry<bool>)ModifyPricesProperty.GetValue(null, null);
		if (val == null || !val.Value)
		{
			return false;
		}
		if (MoonPricesField.GetValue(null) is Dictionary<ExtendedLevel, int> dictionary)
		{
			return dictionary.TryGetValue(level, out value);
		}
		return false;
	}

	private void OnDestroy()
	{
		Log.LogInfo((object)"Bridge bootstrap destroyed; retaining hooks until Application.quitting.");
	}

	private void Shutdown()
	{
		if (cleanedUp)
		{
			return;
		}
		cleanedUp = true;
		Application.quitting -= Shutdown;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		foreach (KeyValuePair<DawnPurchaseInfo, Binding> item in Bound)
		{
			if (object.ReferenceEquals(PredicateField.GetValue(item.Key), item.Value.Guard))
			{
				PredicateField.SetValue(item.Key, item.Value.OriginalPredicate);
			}
			if (object.ReferenceEquals(CostField.GetValue(item.Key), item.Value.Price))
			{
				CostField.SetValue(item.Key, item.Value.OriginalPrice);
			}
		}
		Bound.Clear();
		lastPending = -1;
	}
}